|
问题描述
现有一棵 n 个节点的树,树上每条边的长度均为 1。给出 m 个询问,每次询问两个节 点 x,y,求树上到 x,y 两个点距离相同的节点数量。
输入格式
第一个整数 n,表示树有 n 个点。
接下来 n-1 行每行两整数 a,b,表示从 a 到 b 有一条边。
接下来一行一个整数 m,表示有 m 个询问。
接下来 m 行每行两整数 x,y,询问到 x 和 y 距离相同的点的数量。
输出格式
共 m 行,每行一个整数表示询问的答案。
样例输入
7
1 2
1 3
2 4
2 5
3 6
3 7
3
1 2
4 5
2 3
思路: 被坑了好久 一直没调出来 复习了一波LCA 后 终于A 了 注意 倍增的用法 即GOUP 操作
顺便复习一下 距离倍增
code:
g[x][i]=g[x][i-1]+g[fa[x][i-1]][i-1];
dis 求法
for(i=0;i<=ss;i++) if(k&(1<<i))dis+=g[x][i],x=fa[x][i]; if(x==y)return dis; for(i=s;i>=0;i--) if(fa[x][i]!=fa[y][i]) { dis+=g[x][i];x=fa[x][i]; dis+=g[y][i];y=fa[y][i]; } return dis+=g[x][0]+g[y][0];
code:
// #include<bits/stdc++.h> using namespace std; #define maxnn 600000 int f[maxnn][100]; int las[maxnn],nex[maxnn],en[maxnn],tot; int n,m; int dep[maxnn]; int x,y; int size[maxnn]; void dfs(int v,int fa) { dep[v]=dep[fa]+1; f[v][0]=fa; int s=ceil(log2(n)); for(int i=1;i<=s;i++) { f[v][i]=f[f[v][i-1]][i-1]; } for(int i=las[v];i;i=nex[i]) { int u=en[i]; if(u!=fa) { dfs(u,v); size[v]+=size[u]; } } return ; } void add(int a,int b) { en[++tot]=b; nex[tot]=las[a]; las[a]=tot; } int goup(int x,int s) { int k=ceil(log2(n)); for(int i=0;i<=k;i++) { if((s&(1<<i))) { x=f[x][i]; } } return x; } int lca(int x,int y) { if(dep[x]<dep[y])swap(x,y); x=goup(x,dep[x]-dep[y]); if(x==y) return y; int s=ceil(log2(dep[x])); for(int i=s;i>=0;i--) { if(f[x][i]!=f[y][i]) { x=f[x][i]; y=f[y][i]; } } return f[x][0]; } int main() { cin>>n; for(int i=1;i<=n;i++) size[i]=1; for(int i=1;i<n;i++) { scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs(1,0); scanf("%d",&m); for(int i=1;i<=m;i++) { int k1=0,k=0; scanf("%d%d",&x,&y); if(y==x) {cout<<n<<endl;continue;} if(dep[x]==dep[y]) { int k=dep[x]-dep[lca(x,y)]; int k1=n-size[goup(x,k-1)]-size[goup(y,k-1)]; cout<<k1<<endl; continue; } if((abs((dep[x]-dep[y])))&1) {cout<<0<<endl;continue;} if(dep[x]<dep[y]) swap(x,y); k=(dep[y]+dep[x]-2*dep[lca(x,y)])/2; int p1=goup(x,k-1);int p2=goup(x,k); k1=size[p2]-size[p1]; cout<<k1<<endl; } }