一九八四

11 篇文章 0 订阅

Tarjan算法

  • 我们发现对于一些在图上操作和查询的问题,有时我们可以通过Tarjan来的实现。
  • 这里我们针对利用Tarjan解决有关图的联通的问题

思路

  • 我们发现把一个图转换成一个树的时候,点的联通情况是不变的。

流程

  • 我们先把图建成树,并且把每个点在那棵树记录下来
  • 对于删边的操作有以下的条件要判断
    • S和T不在一棵树 false
    • 边不是树上的边 true
    • 如果 S,T 都不在 dfn[a,b] true
    • 如果 dfn[S](dep[S]>=dep[T])<low[S] 即S可以跳出去 true
  • 对于删点 a 的操作有三种情况
    • S,T都在 dfna true
    • S,T 都在 dfna 中 我们把 S,T 沿着树走到 a 下,如果点一样或者都可以跳出去 true
    • S,T 其一在 dfna 把它沿着树走到 a 下如果可以跳出去true
    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+5,M=5e5+5,S=18; 
    int h[M*2],g[M*2],nx[M*2],tot;
    void Add(){
        int x,y;scanf("%d %d",&x,&y);
        g[++tot]=y,nx[tot]=h[x],h[x]=tot;
        g[++tot]=x,nx[tot]=h[y],h[y]=tot;
    }
    void Min(int &a,int b){if(a>b)a=b;}
    int Dfn,dfn[N],low[N],R[N],T[N],dep[N],fa[N][S],Tcnt;
    int n,m,cmd;
    //void dfs(int x,int c){
    //  T[x]=c;
    //  dfn[x]=low[x]=++Dfn;
    //  for(int i=h[x];i;i=nx[i])if(g[i]!=fa[x][0]){
    //      int y=g[i];
    //      if(dfn[y])Min(low[x],low[y]);
    //      else{
    //          fa[y][0]=x,dep[y]=dep[x]+1;
    //          dfs(y,c);Min(low[x],dfn[y]);
    //      }
    //  }R[x]=Dfn;
    //}
    void dfs(int x,int c){
        T[x]=c;dfn[x]=low[x]=++Dfn;
        for(int i=h[x];i;i=nx[i]){
            int to=g[i];
            if(to==fa[x][0])continue;
            if(!dfn[to]){
                fa[to][0]=x,dep[to]=dep[x]+1;
                dfs(to,c);
                low[x]=min(low[x],low[to]);
            }else low[x]=min(low[x],dfn[to]);
        }R[x]=Dfn;
    }
    int Up(int x,int p){
        for(int i=0;i<S;i++)
            if(p&(1<<i))x=fa[x][i];
        return x;
    }
    void upto(int &x,int y){
        int s=dep[x]-dep[y]-1;
        if(s<=0)return;
        for(int i=0;i<S;i++)
            if(s&(1<<i))x=fa[x][i];
    }       
    void Init(){
        for(int i=0;i<S-1;i++)
            for(int j=1;j<=n;j++)
                fa[j][i+1]=fa[fa[j][i]][i];
    }   
    bool In(int s,int f){
        return dfn[f]<=dfn[s]&&dfn[s]<=R[f];
    }
    bool Cmd1(){
        int a,b,x,y;
        scanf("%d %d %d %d",&a,&b,&x,&y);
    
        if(T[a]!=T[b])return 0;
        if(T[a]!=T[y])return 1;
    
        if(dep[x]>dep[y])swap(x,y);
    
        if(fa[y][0]!=x)return 1;//非树边 
    
        if((In(a,y)&&In(b,y))||(!In(a,y)&&!In(b,y)))return 1;
    
        if(low[y]<dfn[y])return 1;//可以直接跑上去 
    
        return 0;
    }
    bool Cmd2(){
        int a,b,x;
        scanf("%d %d %d",&a,&b,&x);
        if(T[a]!=T[b])return 0;
        if(T[x]!=T[a])return 1;
        if(!In(a,x)&&!In(b,x))return 1;
        if(In(a,x)&&In(b,x)){
            upto(a,x),upto(b,x);
            if(a==b||(low[a]<dfn[x]&&low[b]<dfn[x]))return 1;
            return 0;
        }
        if(In(a,x)){
            upto(a,x);
            return low[a]<dfn[x];
        }else{
            upto(b,x);
            return low[b]<dfn[x];
        }
    
    }
    int main(){
        scanf("%d %d",&n,&m);
        while(m--)Add();
        for(int i=1;i<=n;i++)
            if(!dfn[i])dfs(i,++Tcnt);
        Init();
        scanf("%d",&m);
        while(m--){
            scanf("%d",&cmd);
            if(cmd==1)puts(Cmd1()?"yes":"no");
            else puts(Cmd2()?"yes":"no");
        }
        return 0;
    }
    
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值