6576: 点的距离 倍增LCA
描述
给定一棵 n 个点的树,Q 个询问,每次询问点 x 到点 y 两点之间的距离。
输入
第一行一个正整数 n,表示这棵树有 n 个节点;
接下来 n−1 行,每行两个整数 x,y表示 x,y 之间有一条连边;
然后一个整数 Q,表示有 Q 个询问;
接下来 Q 行每行两个整数 x,y 表示询问 x 到 y 的距离。
对于全部数据,1≤n≤105,1≤x,y≤n
输出
输出 Q 行,每行表示每个询问的答案。
样例输入
6
1 2
1 3
2 4
2 5
3 6
2
2 6
5 6
样例输出
3
4
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e5+10,inf = 0x3f3f3f3f; struct node{ int to,next,w; //to:第cnt条边的终点 //next:第cnt条边的起点的上一条边是第几条边 //w:第cnt条边的权值 }; node edge[2 * N]; int head[2 * N],cnt = 1; //链式前向星数组大小2 * N,边数从1开始 int n,m,x,y; int dep[N],f[N][21]; //dep[i]第i个点当前的深度,f[i][k]表示第i个点向上2^k层的父节点是谁 void add(int u,int v) { edge[cnt].to = v; edge[cnt].next = head[u]; head[u] = cnt++; } void init(int u,int fa) { dep[u] = dep[fa] + 1; for(int i = 1; (1<<i) <= dep[u]; i++) f[u][i] = f[f[u][i - 1]][i - 1]; for(int i = head[u]; i; i = edge[i].next) { int v = edge[i].to; if(v == fa)continue; f[v][0] = u; init(v,u); } } int lca(int x,int y) { if(dep[x] < dep[y])swap(x,y); for(int i = 20; i >= 0; i--) { if(dep[f[x][i]] >= dep[y]) x = f[x][i]; //深度还没有统一 if(x == y)return x; } for(int i = 20; i >= 0; i--) { if(f[x][i] != f[y][i]) { x = f[x][i],y = f[y][i]; } } return f[x][0]; //x往前再走一步就是x,y的最近公共祖先 } int dist(int x,int y) { return dep[x] + dep[y] - 2 * dep[lca(x,y)]; } int main() { cin >> n; for(int i = 1; i < n; i++) { scanf("%d %d",&x,&y); add(x,y); add(y,x); } init(1,0); cin >> m; while(m--) { scanf("%d %d",&x,&y); printf("%d\n",dist(x,y)); } return 0; }