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; }