首页 > 代码库 > 3069: [Pa2011]Hard Choice 艰难的选择

3069: [Pa2011]Hard Choice 艰难的选择

Description

Byteasar是一个很纠结的人。每次他经过Bytetown的时候都知道有至少2条不同的路径可以选择,这导致他必须花很长时间来决定走哪条路。Byteasar最近听说了Bytetown的修路计划,他可能是唯一一个为此感到高兴的人——他有机会消除他的烦恼。

在Byteasar一共有n个岔口,连接着m条双向道路。两条路径完全不同当且仅当他们没有公共的道路(但是允许经过相同的岔口)。

Byteasar想知道:对于两个岔口x y,是否存在一对完全不同的路径。

Input

第一行3个整数:n, m, z (2<=n<=100000, 1<=m,z<=100000),分别代表:n个岔口,m条边,事件数z。岔口编号为1~n。

下面m行:ai, bi (1<=ai,bi<= n, ai!=bi),描述一条边

然后下面z行描述事件:ti, ci, di (t=‘Z‘ or ‘P‘, 1<=ci,di<=n, ci!=di)。事件按照时间排序。

  • t=‘Z‘,表示删除一条边(ci, di),保证这条边之前没有被删除。注意,边可以被全部删除!
  • t=‘P‘,询问是否存在从ci到di的一对完全不同的路径。

Output

对于每组询问,如果存在,输出TAK,否则输出NIE

逆着操作顺序加边,同时并查集维护连通性和边双连通分量
预处理出按加边顺序得到的生成森林,在上面把每个连通块定向为有根树并标上深度
正式加边时,若两侧不连通则标为联通,否则将边的两端在生成树上的路径并成同一个边双连通分量
查询时可以直接判断两点是否在同个边双连通分量内

#include<bits/stdc++.h>char buf[5000000],*ptr=buf-1;int _(){    int x=0,c=*++ptr;    while(c<48)c=*++ptr;    while(c>47)x=x*10+c-48,c=*++ptr;    return x;}int _o(){    int c=*++ptr;    while(c<A||c>Z)c=*++ptr;    return c;}const int N=100007;int es[N*2],enx[N*2],ev[N*2],e0[N],ep=2,del[N];int n,m,q,qs[N][3],f1[N],f2[N],fa[N],ap=0,dep[N];bool ed[N],as[N];int get(int*f,int x){    int a=x,c;    while(x!=f[x])x=f[x];    while(x!=f[a])c=f[a],f[a]=x,a=c;    return x;}struct edge{    int a,b,id;    bool operator<(edge e)const{return a!=e.a?a<e.a:b<e.b;}    void chk(){        int x=get(f1,a),y=get(f1,b);        if(x!=y){            f1[x]=y;            ev[id<<1]=ev[id<<1|1]=1;        }    }    void ins(){        int x=get(f1,a),y=get(f1,b);        if(x!=y){            f1[x]=y;            return;        }        a=get(f2,a);b=get(f2,b);        while(a!=b){            if(dep[a]<dep[b])b=f2[b]=get(f2,fa[b]);            else a=f2[a]=get(f2,fa[a]);        }    }}e[N];void dfs(int w){    ed[w]=1;    for(int i=e0[w];i;i=enx[i]){        int u=es[i];        if(!ed[u]&&ev[i])fa[u]=w,dep[u]=dep[w]+1,dfs(u);    }}void ae(){    int a=_(),b=_();    if(a>b)std::swap(a,b);     e[ep>>1]=(edge){a,b,ep>>1};    es[ep]=b;enx[ep]=e0[a];e0[a]=ep++;    es[ep]=a;enx[ep]=e0[b];e0[b]=ep++;}void query(int a,int b){    as[ap++]=(get(f2,a)==get(f2,b));}int main(){    fread(buf,1,sizeof(buf),stdin);    n=_();m=_();q=_();    for(int i=1;i<=m;++i)ae();    std::sort(e+1,e+m+1);    for(int i=1,a,b;i<=q;++i){        if(qs[i][0]=(_o()==Z)){            a=_();b=_();            if(a>b)std::swap(a,b);            a=std::lower_bound(e+1,e+m+1,(edge){a,b})-e;            ++del[a];            qs[i][1]=a;        }else{            qs[i][1]=_();            qs[i][2]=_();        }    }    for(int i=1;i<=n;++i)f1[i]=i;    for(int i=1;i<=m;++i){        while(del[i])i+=del[i];        if(i<=m)e[i].chk();    }    for(int i=q;i;--i)if(qs[i][0])e[qs[i][1]].chk();    for(int i=1;i<=n;++i)if(!ed[i])dfs(i);    for(int i=1;i<=n;++i)f1[i]=f2[i]=i;    for(int i=1;i<=m;++i){        while(del[i])i+=del[i];        if(i<=m)e[i].ins();    }    for(int i=q;i;--i)if(qs[i][0])e[qs[i][1]].ins();else query(qs[i][1],qs[i][2]);    while(ap)puts(as[--ap]?"TAK":"NIE");    return 0;}

 

3069: [Pa2011]Hard Choice 艰难的选择