1. 程式人生 > >樹上倍增求LCA

樹上倍增求LCA

oid void for print names != ostream tmp iostream

大概思想就是,節點$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 */

樹上倍增求LCA