大概思想就是,节点$i$的第$2^{j}$个父节点是他第$2^{j-1}$个父亲的第$2^{j-1}$个父亲
然后可以$O(nlogn)$时间内解决……
没了?
1 //fa[i][j]表示i的第2^j个父节点 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #include<cmath> 6 using namespace std; 7 struct edge{ 8 int v,next; 9 }a[100001]; 10 int n,q,u,v,rt,tot=0,head[100001],fa[100001][31],dep[100001]; 11 bool vis[100001]; 12 void add(int u,int v){ 13 a[++tot].v=v; 14 a[tot].next=head[u]; 15 head[u]=tot; 16 } 17 void cal_dep(int u){ 18 vis[u]=true; 19 for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){ 20 int v=a[tmp].v; 21 if(!vis[v]){ 22 dep[v]=dep[u]+1; 23 cal_dep(v); 24 } 25 } 26 } 27 void cal(){ 28 for(int j=1;j<=30;j++){ 29 for(int i=1;i<=n;i++){ 30 fa[i][j]=fa[fa[i][j-1]][j-1]; 31 } 32 } 33 } 34 int lca(int x,int y){ 35 if(dep[x]<dep[y]){ 36 swap(x,y); 37 } 38 int s=dep[x]-dep[y]; 39 for(int i=0;i<30;i++){ 40 if((1<<i)&s)x=fa[x][i]; 41 } 42 if(x==y)return x; 43 for(int i=29;i>=0;i--){ 44 if(fa[x][i]!=fa[y][i]){ 45 x=fa[x][i]; 46 y=fa[y][i]; 47 } 48 } 49 return fa[x][0]; 50 } 51 int main(){ 52 memset(head,-1,sizeof(head)); 53 memset(fa,0,sizeof(fa)); 54 memset(dep,0,sizeof(dep)); 55 memset(vis,0,sizeof(vis)); 56 scanf("%d%d",&n,&q); 57 for(int i=1;i<n;i++){ 58 scanf("%d%d",&u,&v); 59 add(u,v); 60 fa[v][0]=u; 61 //if(!fa[u][0])rt=u; 62 } 63 dep[1]=1; 64 cal_dep(1); 65 cal(); 66 for(int i=1;i<=q;i++){ 67 scanf("%d%d",&u,&v); 68 printf("%d\n",lca(u,v)); 69 } 70 return 0; 71 } 72 /* 73 16 4 74 1 2 75 1 3 76 2 4 77 2 5 78 2 6 79 3 7 80 4 8 81 4 9 82 5 10 83 7 11 84 7 12 85 10 13 86 10 14 87 10 15 88 12 16 89 4 7 90 9 16 91 11 16 92 15 8 93 ------ 94 1 95 1 96 7 97 2 98 */
原文地址:https://www.cnblogs.com/dcdcbigbig/p/8952821.html
时间: 2024-10-22 21:55:15