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 }
原文地址:https://www.cnblogs.com/WABoss/p/5467879.html