【bzoj4229】选择 离线+LCT

时间:2023-03-10 06:41:33
【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;
}