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;
}
原文地址:https://www.cnblogs.com/ccz181078/p/6339946.html