bzoj 4229 选择

http://www.elijahqi.win/archives/3238
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
Sample Input

7 8 7
1 2
1 3
1 4
2 3
3 4
3 7
7 4
5 6
Z 1 4
P 1 3
P 2 4
Z 1 3
P 1 3
Z 6 5
P 5 6
Sample Output

Yes
Yes
No
No
HINT

对于全部数据,max(n,m,q)<=100000
删边 不好做 改为离线 变成加边 然后动态维护边双联通分量即可
具体维护方法参见
https://blog.csdn.net/elijahqi/article/details/79327675

#include<map>
#include<queue>
#include<cstdio>
#include<cctype>
#include<algorithm>
#define pa pair<int,int>
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();}
    while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
    return x*f;
}
const int N=1e5+10;
map<pa,int> mm;
map<pa,int>:: iterator it;
int fa[N],fa1[N],fa2[N],n,m,Q,c[N][2],q[N],top,cnt;bool rev[N];
inline int find1(int x){
    while(x!=fa1[x]) x=fa1[x]=fa1[fa1[x]];return x;
}
inline int find2(int x){
    while(x!=fa2[x]) x=fa2[x]=fa2[fa2[x]];return x;
}
inline bool isroot(int x){
    return c[find2(fa[x])][0]!=x&&c[find2(fa[x])][1]!=x;
}
inline void pushdown(int x){
    if (!rev[x]) return;rev[x]^=1;int l=c[x][0],r=c[x][1];
    rev[l]^=1;rev[r]^=1;swap(c[x][0],c[x][1]);
}
inline void rotate(int x){
    int y=find2(fa[x]),z=find2(fa[y]),l=c[y][1]==x,r=l^1;
    if (!isroot(y)) c[z][c[z][1]==y]=x;
    fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
    c[y][l]=c[x][r];c[x][r]=y;
}
inline void splay(int x){
    q[top=1]=x;for (int i=x;!isroot(i);i=find2(fa[i])) 
    q[++top]=find2(fa[i]);
    while(top) pushdown(q[top--]);
    while(!isroot(x)){
        int y=find2(fa[x]),z=find2(fa[y]);
        if (!isroot(y)){
            if (c[y][0]==x^c[z][0]==y) rotate(x);else rotate(y);
        }rotate(x);
    }
}
inline void access(int x){
    for (int t=0;x;t=x,x=find2(fa[x])) splay(x),c[x][1]=t;
}
inline void makeroot(int x){
    access(x);
    splay(x);
    rev[x]^=1;
}
inline void link(int x,int y){
    fa1[find1(x)]=find1(y);
    makeroot(x);fa[x]=y;
}
inline void dfs(int x,int f){
    fa2[x]=f;if (c[x][0]) dfs(c[x][0],f);if (c[x][1]) dfs(c[x][1],f);
}
inline void insert1(int x,int y){
    x=find2(x);y=find2(y);if (x==y) return;
    if (find1(x)!=find1(y)) {link(x,y);return;}
    makeroot(x);
    access(y);
    splay(y);
    dfs(c[y][0],y);
}
struct node{int x,y,op,id;}qr[N];// op=0? print:del
bool ans[N];
int main(){
    freopen("bzoj4229.in","r",stdin);
    n=read();m=read();Q=read();
    for (int i=1;i<=n;++i) fa1[i]=fa2[i]=i;
    for (int i=1;i<=m;++i){
        static int x,y;x=read();y=read();
        if (x>y) swap(x,y);++mm[make_pair(x,y)];
    }
    for (int i=1;i<=Q;++i){
        static char ch;static int x,y;
        ch=gc();while(ch!='Z'&&ch!='P') ch=gc();
        if (ch=='P')qr[i].x=read(),qr[i].y=read(),qr[i].op=0,qr[i].id=++cnt;
        else{
            x=read();y=read();if (x>y) swap(x,y);--mm[make_pair(x,y)];
            qr[i].op=1;qr[i].x=x;qr[i].y=y;
        }
    }
    for (it=mm.begin();it!=mm.end();++it){static int tim,x,y;
        tim=it->second;x=it->first.first;y=it->first.second;
//      printf("%d %d %d\n",tim,x,y);
        for (int j=1;j<=tim;++j) insert1(x,y);
    }
//  printf("%d %d %d\n",find2(3),find2(4),find2(7));
    for (int i=Q;i;--i){
        if (!qr[i].op) ans[qr[i].id]=(find2(qr[i].x)==find2(qr[i].y));
        else insert1(qr[i].x,qr[i].y);
    }
    for (int i=1;i<=cnt;++i) ans[i]?puts("Yes"):puts("No");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值