zoukankan      html  css  js  c++  java
  • bzoj4229: 选择

    Description

    现在,我想知道自己是否还有选择。
    给定n个点m条边的无向图以及顺序发生的q个事件。
    每个事件都属于下面两种之一:
    1、删除某一条图上仍存在的边
    2、询问是否存在两条边不相交的路径可以从点u出发到点v

    Input

    第一行三个整数n,m,q
    接下来m行,每行两个整数u,v,表示u和v之间有一条边
    接下来q行,每行一个大写字母o和2个整数u、v,依次表示按顺序发生的q个事件:
    当o为’Z’时,表示删除一条u和v之间的边
    当o为’P’时,表示询问是否存在两条边不相交的路径可以从点u出发到点v

    Output

    对于每组询问,如果存在,输出Yes,否则输出No
    倒着模拟,首先求出所有操作后的连通块并缩点,按删边倒序对缩点后的图加边(A)但保证不成环,过程并查集维护
    保留连通块内的边和A类边,dfs一次求出某棵生成树内每个点的深度和父节点,顺便对每个连通块(所有操作后的,不包含A边)用tarjan求边双连通分量
    再一次倒序加边,此时并查集维护每个点所属边双连通分量内深度最小的点,加边时在树上求lca并沿路径缩点(整条路径加边后成为同一边双连通分量)
    #include<cstdio>
    #include<algorithm>
    const int N=100010,M=10000000;
    char buf[M+2],*ptr=buf-1;
    inline int _int(){
        int x=0,c=*++ptr;
        while(c>57||c<48)c=*++ptr;
        while(c>47&&c<58)x=x*10+c-48,c=*++ptr;
        return x;
    }
    inline int getop(){
        int c=*++ptr;
        while(c<'A'||c>'Z')c=*++ptr;
        return c;
    }
    struct edge{int a,b;}e[100010];
    bool operator<(edge a,edge b){
        return a.a!=b.a?a.a<b.a:a.b<b.b;
    }
    int n,m,q;
    int qs[N][3];
    bool ans[N];
    int del[N];
    int es[N*2],enx[N*2],e0[N],ep=2,f[N],F[N],F1[N],dep[N],fa[N];
    int ed[N*2];
    int dfn[N],low[N],T=0;
    int get(int x){
        int a=x,c;
        while(x!=f[x])x=f[x];
        while(x!=(c=f[a]))f[a]=x,a=c;
        return x;
    }
    int Get(int x){
        int a=x,c;
        while(x!=F[x])x=F[x];
        while(x!=(c=F[a]))F[a]=x,a=c;
        return x;
    }
    void swap(int&a,int&b){int c=a;a=b;b=c;}
    void tj(int w){
        dfn[w]=low[w]=++T;
        for(int i=e0[w];i;i=enx[i]){
            int u=es[i];
            if(ed[i]){
                if(ed[i]==2&&!dfn[u]){
                    dep[u]=dep[w]+1;
                    fa[u]=w;
                    tj(u);
                }
                continue;
            }
            if(!dfn[u]){
                ed[i^1]=1;
                dep[u]=dep[w]+1;
                fa[u]=w;
                tj(u);
                if(low[u]<low[w])low[w]=low[u];
                if(low[u]<=dfn[w])f[get(u)]=get(w);
            }else if(dfn[u]<low[w])low[w]=dfn[u];
        }
    }
    int main(){
        fread(buf,1,M,stdin);
        n=_int();m=_int();q=_int();
        for(int i=0;i<m;i++){
            int a=_int(),b=_int();
            if(a>b){int c=a;a=b;b=c;}
            e[i]=(edge){a,b};
        }
        std::sort(e,e+m);
        for(int i=1;i<=q;i++){
            qs[i][0]=(getop()=='Z');
            int a=qs[i][1]=_int();
            int b=qs[i][2]=_int();
            if(qs[i][0]){
                if(a>b)swap(a,b);
                edge w=(edge){a,b};
                ++del[std::lower_bound(e,e+m,w)-e];
            }
        }
        for(int i=1;i<=n;i++)F[i]=f[i]=i;
        for(int i=0;i<m;i++){
            if(del[i]>1)for(int j=0,c=del[i];j<c;j++)del[i+j]=1;
            if(del[i])continue;
            int a=e[i].a,b=e[i].b;
            es[ep]=b;enx[ep]=e0[a];e0[a]=ep++;
            es[ep]=a;enx[ep]=e0[b];e0[b]=ep++;
            F[Get(a)]=Get(b);
        }
        for(int i=1;i<=n;i++)F1[i]=F[i];
        for(int i=q;i;i--)if(qs[i][0]){
            int a=qs[i][1],b=qs[i][2];
            if(Get(a)==Get(b))continue;
            ed[ep]=2;es[ep]=b;enx[ep]=e0[a];e0[a]=ep++;
            ed[ep]=2;es[ep]=a;enx[ep]=e0[b];e0[b]=ep++;
            F[Get(a)]=Get(b);
        }
        for(int i=1;i<=n;i++)if(!dfn[i])tj(i);
        for(int i=1;i<=n;i++)F[i]=F1[i];
        for(int i=q;i;i--){
            int a=qs[i][1],b=qs[i][2];
            if(qs[i][0]){
                if(Get(a)!=Get(b)){
                    if(dep[a]<dep[b])swap(a,b);
                    fa[a]=b;
                    F[Get(a)]=Get(b);
                    continue;
                }
                a=get(a);b=get(b);
                while(a!=b){
                    if(dep[a]<dep[b])swap(a,b);
                    f[a]=get(fa[a]);
                    a=fa[a];
                }
            }else ans[i]=(get(a)==get(b));
        }
        for(int i=1;i<=q;i++)if(!qs[i][0])puts(ans[i]?"Yes":"No");
        return 0;
    }
  • 相关阅读:
    France '98
    【笔记】《通俗详细地讲解什么是P和NP问题》的概念记录
    130831组队赛-Regionals 2011, Asia
    Android 解屏幕锁与点亮屏幕
    Android 点亮屏幕
    利用FFT 计算生成离散解析信号
    hdu5246 超级赛亚ACMer
    用srvctl命令配置service
    MySQL优化之——权限管理
    JS 点击复制Copy插件--Zero Clipboard
  • 原文地址:https://www.cnblogs.com/ccz181078/p/5628022.html
Copyright © 2011-2022 走看看