bzoj4229: 选择

Posted ccz181078

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}

 

以上是关于bzoj4229: 选择的主要内容,如果未能解决你的问题,请参考以下文章

VS2008 C ++警告LNK4229:无效指令

VSCode自定义代码片段——CSS选择器

VSCode自定义代码片段6——CSS选择器

Bzoj2339--Hnoi2011卡农

微信小程序代码片段

[bzoj1966][Ahoi2005][VIRUS 病毒检测] (字符串dp)