Gym100685G Gadget Hackwrench(倍增LCA)
题目大概说一棵边有方向的树,q个询问,每次询问结点u是否能走到v。
倍增LCA搞即可:
- 除了par[k][u]表示u结点往上走2k步到达的结点,
- 再加上upp[k][u]表示u结点往上走2k步经过边的状态:-1表示边都是向下,1表示都是向上,0混合。
- 这样u、v都往LCA上走就能知道u是否能走到v了。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define MAXN 111111 6 7 struct Edge{ 8 int v,w,next; 9 }edge[MAXN<<1]; 10 int NE,head[MAXN]; 11 void addEdge(int u,int v,int w){ 12 edge[NE].v=v; edge[NE].w=w; edge[NE].next=head[u]; 13 head[u]=NE++; 14 } 15 16 int dep[MAXN],par[17][MAXN],upp[17][MAXN]; 17 void dfs(int u,int fa){ 18 for(int i=head[u]; i!=-1; i=edge[i].next){ 19 int v=edge[i].v; 20 if(v==fa) continue; 21 dep[v]=dep[u]+1; 22 par[0][v]=u; 23 upp[0][v]=edge[i].w; 24 dfs(v,u); 25 } 26 } 27 28 void init(int n){ 29 for(int i=1; i<17; ++i){ 30 for(int j=1; j<=n; ++j){ 31 if(par[i-1][j]==0){ 32 par[i][j]=0; 33 continue; 34 } 35 par[i][j]=par[i-1][par[i-1][j]]; 36 if(upp[i-1][j]==1 && upp[i-1][par[i-1][j]]==1){ 37 upp[i][j]=1; 38 }else if(upp[i-1][j]==-1 && upp[i-1][par[i-1][j]]==-1){ 39 upp[i][j]=-1; 40 }else{ 41 upp[i][j]=0; 42 } 43 } 44 } 45 } 46 bool lca(int u,int v){ 47 if(dep[u]>dep[v]){ 48 for(int i=0; i<17; ++i){ 49 if((dep[u]-dep[v])>>i&1){ 50 if(upp[i][u]!=1) return 0; 51 u=par[i][u]; 52 } 53 } 54 if(u==v) return 1; 55 for(int i=16; i>=0; --i){ 56 if(par[i][u]!=par[i][v]){ 57 if(upp[i][u]!=1 || upp[i][v]!=-1) return 0; 58 u=par[i][u]; v=par[i][v]; 59 } 60 } 61 if(upp[0][u]!=1 || upp[0][v]!=-1) return 0; 62 }else{ 63 for(int i=0; i<17; ++i){ 64 if((dep[v]-dep[u])>>i&1){ 65 if(upp[i][v]!=-1) return 0; 66 v=par[i][v]; 67 } 68 } 69 if(u==v) return 1; 70 for(int i=16; i>=0; --i){ 71 if(par[i][u]!=par[i][v]){ 72 if(upp[i][u]!=1 || upp[i][v]!=-1) return 0; 73 u=par[i][u]; v=par[i][v]; 74 } 75 } 76 if(upp[0][u]!=1 || upp[0][v]!=-1) return 0; 77 } 78 return 1; 79 } 80 81 int main(){ 82 int n,q,a,b; 83 while(~scanf("%d",&n)){ 84 NE=0; 85 memset(head,-1,sizeof(head)); 86 for(int i=1; i<n; ++i){ 87 scanf("%d%d",&a,&b); 88 addEdge(a,b,-1); 89 addEdge(b,a,1); 90 } 91 92 dfs(1,1); 93 init(n); 94 95 scanf("%d",&q); 96 while(q--){ 97 scanf("%d%d",&a,&b); 98 if(lca(a,b)) puts("Yes"); 99 else puts("No"); 100 } 101 } 102 return 0; 103 }