• 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 }
  • 相关阅读:
    网盘搜索网站汇总
    AutoIt3病毒杀毒攻略(详)
    数据库的逻辑结构设计
    Oracle数据类型
    选择ORACLE数据库字符集
    ETL讲解(很详细!!!)
    Oracle左连接,右连接,全外连接和+号的用法
    Oracle用户创建及权限设置
    内连接、外连接、自然连接
    关系数据库关系代数
  • 原文地址:https://www.cnblogs.com/WABoss/p/5467879.html
Copyright © 2020-2023  润新知