【bzoj4229】选择 离线+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
样例输出
Yes
Yes
No
No
题解
离线+LCT
删边很难处理,考虑离线,时间倒流,把删边变为加边处理。
那么问题就转化为 【bzoj4998】星球联盟 。
使用LCT,加边时如果属于同一连通块,则把路径上的点缩成一个边双。并使用并查集维护边双。
时间复杂度 $O(LCT·n\log n)$
#include <set> #include <cstdio> #define N 100010 using namespace std; set<pair<int , int> > s; int fc[N] , fv[N] , fa[N] , c[2][N] , rev[N] , px[N] , py[N] , opt[N] , qx[N] , qy[N] , ans[N]; char str[5]; int findc(int x) { return x == fc[x] ? x : fc[x] = findc(fc[x]); } int findv(int x) { return x == fv[x] ? x : fv[x] = findv(fv[x]); } inline void pushdown(int x) { if(rev[x]) { swap(c[0][c[0][x]] , c[1][c[0][x]]) , rev[c[0][x]] ^= 1; swap(c[0][c[1][x]] , c[1][c[1][x]]) , rev[c[1][x]] ^= 1; rev[x] = 0; } } inline bool isroot(int x) { return c[0][findv(fa[x])] != x && c[1][findv(fa[x])] != x; } void update(int x) { if(!isroot(x)) update(findv(fa[x])); pushdown(x); } inline void rotate(int x) { int y = findv(fa[x]) , z = findv(fa[y]) , l = (c[1][y] == x) , r = l ^ 1; if(!isroot(y)) c[c[1][z] == y][z] = x; fa[x] = z , fa[y] = x , fa[c[r][x]] = y , c[l][y] = c[r][x] , c[r][x] = y; } inline void splay(int x) { int y , z; update(x); while(!isroot(x)) { y = findv(fa[x]) , z = findv(fa[y]); if(!isroot(y)) { if((c[0][y] == x) ^ (c[0][z] == y)) rotate(x); else rotate(y); } rotate(x); } } inline void access(int x) { int t = 0; while(x) splay(x) , c[1][x] = t , t = x , x = findv(fa[x]); } inline void makeroot(int x) { access(x) , splay(x); swap(c[0][x] , c[1][x]) , rev[x] ^= 1; } void dfs(int x) { if(!x) return; if(fa[x]) fv[x] = findv(fa[x]); dfs(c[0][x]) , dfs(c[1][x]); } inline void link(int x , int y) { x = findv(x) , y = findv(y); if(findc(x) != findc(y)) makeroot(x) , fa[x] = y , fc[fc[x]] = fc[y]; else if(x != y) makeroot(x) , access(y) , splay(y) , dfs(y); } int main() { int n , m , q , i; scanf("%d%d%d" , &n , &m , &q); for(i = 1 ; i <= n ; i ++ ) fc[i] = fv[i] = i; for(i = 1 ; i <= m ; i ++ ) scanf("%d%d" , &px[i] , &py[i]); for(i = 1 ; i <= q ; i ++ ) { scanf("%s%d%d" , str , &qx[i] , &qy[i]); if(str[0] == 'Z') opt[i] = 1 , s.insert(make_pair(min(qx[i] , qy[i]) , max(qx[i] , qy[i]))); } for(i = 1 ; i <= m ; i ++ ) if(s.find(make_pair(min(px[i] , py[i]) , max(px[i] , py[i]))) == s.end()) link(px[i] , py[i]); for(i = q ; i ; i -- ) { if(opt[i]) link(qx[i] , qy[i]); else ans[i] = (findv(qx[i]) == findv(qy[i])); } for(i = 1 ; i <= q ; i ++ ) if(!opt[i]) puts(ans[i] ? "Yes" : "No"); return 0; }