作什麼題都要注意數組的大小,不要犯下數組越界的錯誤(舒適(狠心)提示);數組
作了好多遍就是不對,原來是【20】的數組,在for下循環1——》20,神奇爆零;spa
連接:https://www.luogu.org/problemnew/show/P3398code
這道題有一個性質:blog
判斷樹上兩條路徑是否有交點或重疊部分,那就是get
有a,b一條路徑,還有c,d這條路徑。string
要是這兩條路徑相交或重合,it
那麼要不是lca(a,b)在cd上,就是lca(c,d)在ab上;io
顯然易得啊(反正我是不會證實,背下來記好了);ast
倍增lcaclass
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=2000050; int pre[maxn],other[maxn],last[maxn],l; int n,q; void add(int x,int y) { l++; pre[l]=last[x]; last[x]=l; other[l]=y; } int dep[maxn],jump[maxn][20]; void dfs(int u) { for(int p=last[u];p;p=pre[p]) { int v=other[p]; if(v==jump[u][0]) continue; dep[v]=dep[u]+1; jump[v][0]=u; dfs(v); } } int lca(int u,int v) { if(dep[u]<dep[v]) swap(u,v); for(int i=0;i<=17;i++) { if((dep[u]-dep[v])&(1<<i)) u=jump[u][i]; } if(u==v) return u; for(int j=17;j>=0;j--) { if(jump[u][j]!=jump[v][j]) { u=jump[u][j]; v=jump[v][j]; } } return jump[u][0]; } int main() { scanf("%d%d",&n,&q); for(int i=1;i<n;i++) { int a,b; scanf("%d%d",&a,&b); add(a,b); add(b,a); } dfs(1); for(int j=1;j<=17;j++)//17就夠了,不要搞什麼20 { for(int i=1;i<=n;i++) { jump[i][j]=jump[jump[i][j-1]][j-1]; } } for(int i=1;i<=q;i++) { int a,b,c,d; scanf("%d%d%d%d",&a,&b,&c,&d); int x=lca(a,b); int y=lca(c,d); int l1=dep[a]+dep[b]-2*dep[x];//a->b路徑長度 int l2=dep[c]+dep[d]-2*dep[y];//c->d路徑長度 if(dep[c]+dep[x]-2*dep[lca(x,c)]+dep[d]+dep[x]-2*dep[lca(x,d)]==l2)//c->x->d==l2 { printf("Y\n"); continue; } if(dep[a]+dep[y]-2*dep[lca(a,y)]+dep[b]+dep[y]-2*dep[lca(y,b)]==l1)//a->y->b==l1,就是兩條線段長度和等於整個線段長度 { printf("Y\n"); continue; } printf("N\n"); } return 0; }