【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;
}

 

 

posted @ 2017-11-24 09:15  GXZlegend  阅读(445)  评论(0编辑  收藏  举报