BZOJ4229选择——LCT+并查集+离线(LCT动态维护边双连通分量)
题目描述
现在,我想知道自己是否还有选择。
给定n个点m条边的无向图以及顺序发生的q个事件。
每个事件都属于下面两种之一:
1、删除某一条图上仍存在的边
2、询问是否存在两条边不相交的路径可以从点u出发到点v
输入
第一行三个整数n,m,q
接下来m行,每行两个整数u,v,表示u和v之间有一条边
接下来q行,每行一个大写字母o和2个整数u、v,依次表示按顺序发生的q个事件:
当o为’Z’时,表示删除一条u和v之间的边
当o为’P’时,表示询问是否存在两条边不相交的路径可以从点u出发到点v
输出
对于每组询问,如果存在,输出Yes,否则输出No
样例输入
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
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
样例输出
Yes
Yes
No
No
Yes
No
No
提示
对于全部数据,max(n,m,q)<=100000
只有删边没有加边,删边并不好做,我们将询问离线倒过来做,这样删边就变成了加边。
之后题目就转化成了BZOJ4998。
#include<set> #include<map> #include<queue> #include<stack> #include<cmath> #include<vector> #include<bitset> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define pr pair<int,int> #define ll long long using namespace std; int g[100010]; int fa[100010]; int f[100010]; int s[100010][2]; int st[100010]; int r[100010]; int n,m,p; int opt; int x,y; set<pr>b; char ch[10]; int ans[100010]; struct miku { int opt; int x,y; }q[100010]; struct Miku { int x,y; }a[100010]; int find(int x) { if(fa[x]==x) { return x; } return fa[x]=find(fa[x]); } int judge(int x) { if(g[x]==x) { return x; } return g[x]=judge(g[x]); } int is_root(int rt) { return rt!=s[find(f[rt])][0]&&rt!=s[find(f[rt])][1]; } int get(int rt) { return rt==s[find(f[rt])][1]; } void pushdown(int rt) { if(r[rt]) { swap(s[rt][0],s[rt][1]); r[s[rt][0]]^=1; r[s[rt][1]]^=1; r[rt]^=1; } } void rotate(int rt) { int fa=find(f[rt]); int anc=find(f[fa]); int k=get(rt); if(!is_root(fa)) { s[anc][get(fa)]=rt; } s[fa][k]=s[rt][k^1]; f[s[fa][k]]=fa; s[rt][k^1]=fa; f[fa]=rt; f[rt]=anc; } void splay(int rt) { int top=0; st[++top]=rt; for(int i=rt;!is_root(i);i=find(f[i])) { st[++top]=find(f[i]); } for(int i=top;i>=1;i--) { pushdown(st[i]); } for(int fa;!is_root(rt);rotate(rt)) { if(!is_root(fa=find(f[rt]))) { rotate(get(fa)==get(rt)?fa:rt); } } } void access(int rt) { for(int x=0;rt;x=rt,rt=find(f[rt])) { splay(rt); s[rt][1]=x; } } void reverse(int rt) { access(rt); splay(rt); r[rt]^=1; } void dfs(int x,int rt) { fa[x]=rt; if(s[x][0]) { dfs(s[x][0],rt); } if(s[x][1]) { dfs(s[x][1],rt); } } void link(int x,int y) { int fx=find(x); int fy=find(y); if(fx!=fy) { if(judge(fx)!=judge(fy)) { reverse(fx); f[fx]=fy; g[g[fx]]=g[fy]; } else { reverse(fx); access(fy); splay(fy); dfs(fy,fy); s[fy][0]=0; } } } int main() { scanf("%d%d%d",&n,&m,&p); for(int i=1;i<=n;i++) { fa[i]=g[i]=i; } for(int i=1;i<=m;i++) { scanf("%d%d",&a[i].x,&a[i].y); } for(int i=1;i<=p;i++) { scanf("%s",ch); scanf("%d%d",&q[i].x,&q[i].y); if(ch[0]=='Z') { q[i].opt=1; b.insert(make_pair(min(q[i].x,q[i].y),max(q[i].x,q[i].y))); } } for(int i=1;i<=m;i++) { if(b.find(make_pair(min(a[i].x,a[i].y),max(a[i].x,a[i].y)))==b.end()) { link(a[i].x,a[i].y); } } for(int i=p;i>=1;i--) { if(q[i].opt) { link(q[i].x,q[i].y); } else { ans[i]=(find(q[i].x)==find(q[i].y)); } } for(int i=1;i<=p;i++) { if(!q[i].opt) { printf(ans[i]?"Yes\n":"No\n"); } } }