先暂时把模板写出来,A几道题再来补充
此模板也是洛谷上的一道模板题
P3379 【模板】最近公共祖先(LCA)
#pragma GCC optimize(2) //o2优化 #include <bits/stdc++.h> using namespace std; typedef long long ll; const int L = 30;//2的指数的大小 const int NN = 1e6+10; int N,M,S; ll bit[L]; int depth[NN];//depth[i]:节点i在树上的深度 int fa[NN][L]; //fa[i][j]:节点i向上走2^j次方的节点 vector<int> G[NN];//存图 void init_log(){//预先把2的多少次方计算出来 bit[0] = 1; for(int i = 1;i<L;i++) bit[i] = bit[i-1]*2; } void DFS(int u,int par){//u:当前节点 par:u的父亲节点 depth[u] = depth[par]+1; fa[u][0] = par; for(int i = 1;i<L;i++){ fa[u][i] = fa[fa[u][i-1]][i-1];//计算u的各次方的祖先 } for(auto v: G[u]){//继续去遍历该节点的孩子节点 if(v!=par){//因为是用邻接表存的,所以需要跳过父亲节点 DFS(v,u); } } } int LCA(int a,int b){ if(depth[a] < depth[b]) swap(a,b);//保证深度大的在前,小的在后 int dif = depth[a] - depth[b];//深度差 for(int i = L-1;i>=0;i--){ if(bit[i] <= dif){//在不超出深度差的范围向上爬 a = fa[a][i];//爬到的位置 dif -= bit[i];//深度差更新 } } //此时a,b已经是相同的深度 if(a == b) return a; //如果a,b节点已经相同,所以a,b所在的节点就是lca for(int i = L-1;i>=0;i--){ if(bit[i] <= depth[a] && fa[a][i] != fa[b][i]){ //bit[i]<=depth[a]:表示不跳出树之外 a = fa[a][i]; b = fa[b][i]; } } return fa[a][0]; //返回lca的儿子的父亲,也就是lca } int main(){ // freopen("test.in","r",stdin); init_log(); cin>>N>>M>>S; int u,v; for(int i = 1;i<=N-1;i++){ //邻接表存图 scanf("%d%d",&u,&v); G[u].push_back(v); G[v].push_back(u); } DFS(S,0); int a,b; for(int i = 1;i<=M;i++){ scanf("%d%d",&a,&b); int lca = LCA(a,b); printf("%d\n",lca); } return 0; }