题意:
给一棵树,每次询问给两个点u,v,求到这两个点距离相等的点的个数。(n,q<=1e5)
题解:
简单题,考虑u,v所在链,如果奇数条边显然ans=0;
偶数条边则这两个点的中点x符合条件,考虑链外还有什么点符合条件:中点x连着的其他子树中的点;
倍增+分类讨论一波;
坑点:u==v时的情况
1 #include<bits/stdc++.h> 2 #define maxn 100005 3 using namespace std; 4 int n,q; 5 struct edge 6 { 7 int to,next; 8 }e[maxn<<1]; 9 int head[maxn],p; 10 void addedge(int u,int v) 11 { 12 e[++p].to=v;e[p].next=head[u];head[u]=p; 13 } 14 int d[maxn],anc[maxn][20],size[maxn]; 15 void dfs(int u,int f) 16 { 17 size[u]=1; 18 d[u]=d[f]+1;anc[u][0]=f; 19 for(int i=head[u];i;i=e[i].next) 20 { 21 int v=e[i].to; 22 if(v==f)continue; 23 dfs(v,u); 24 size[u]+=size[v]; 25 } 26 } 27 void predp() 28 { 29 for(int j=1;j<=18;++j) 30 for(int i=1;i<=n;++i)anc[i][j]=anc[anc[i][j-1]][j-1]; 31 } 32 int lca(int u,int v) 33 { 34 if(d[u]<d[v])swap(u,v); 35 for(int i=18;i>=0;--i)if(d[anc[u][i]]>=d[v])u=anc[u][i]; 36 if(u==v)return u; 37 for(int i=18;i>=0;--i)if(anc[u][i]!=anc[v][i])u=anc[u][i],v=anc[v][i]; 38 return anc[u][0]; 39 } 40 int getanc(int x,int k) 41 { 42 for(int i=18;i>=0;--i)if(k>=(1<<i))x=anc[x][i],k-=(1<<i); 43 return x; 44 } 45 int main() 46 { 47 scanf("%d",&n); 48 for(int i=1;i<n;++i) 49 { 50 int u,v; 51 scanf("%d%d",&u,&v); 52 addedge(u,v); 53 addedge(v,u); 54 } 55 dfs(1,0); 56 predp(); 57 scanf("%d",&q); 58 while(q--) 59 { 60 int u,v; 61 scanf("%d%d",&u,&v); 62 int t=lca(u,v); 63 int dis1=d[u]-d[t],dis2=d[v]-d[t]; 64 int ans; 65 if(u==v)ans=n; 66 else if(dis1==dis2) 67 { 68 int x=getanc(u,dis1-1); 69 int y=getanc(v,dis2-1); 70 ans=n-size[x]-size[y]; 71 } 72 else 73 { 74 if((dis1+dis2)&1)ans=0; 75 else 76 { 77 int D=(dis1+dis2)/2; 78 if(d[u]<d[v])swap(u,v); 79 int x=getanc(u,D); 80 int y=getanc(u,D-1); 81 ans=size[x]-size[y]; 82 } 83 } 84 printf("%d ",ans); 85 } 86 return 0; 87 }