[BZOJ2049]SDOI2008洞穴勘测|LCT|并查集

LCT或者按秩合并的并查集维护一下联通性就行了。。

LCT:

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=10005,MAX=999999999;
int c[maxn][2],pre[maxn],isroot[maxn],rev[maxn],n,m,u,v,i;
char com[10];
void mark(int x)
{if (!x) return;
swap(c[x][0],c[x][1]);
rev[x]^=1;
}
void update(int x)
{if (rev[x])
	{mark(c[x][0]);mark(c[x][1]);
	rev[x]=0;
	}
}
void rotate(int x,int kind)
{int y=pre[x],z=pre[y];
update(y);update(x);
pre[y]=x;pre[x]=z;
c[y][!kind]=c[x][kind];
pre[c[x][kind]]=y;
c[x][kind]=y;
if (z&&!isroot[y]) c[z][c[z][1]==y]=x;
if (isroot[y])
	{isroot[y]=0;
	isroot[x]=1;
	}
}
void splay(int x)
{update(x);
while (!isroot[x])
	{//printf("%d %d %d %d %d %d\n",x,pre[x],c[x][0],c[x][1],rev[x],isroot[x]);
	int y=pre[x],z=pre[y];
	if (z) update(z);	
	update(y);
	if (isroot[y]) rotate(x,c[y][0]==x);
	else 
		{int kind=c[y][0]==x;
		if (c[z][kind]==y)
			{rotate(x,kind);
			rotate(x,!kind);
			}
		else 
			{rotate(y,kind);
			rotate(x,kind);
			}
		}
	}
}
void access(int x)
{splay(x);
update(x);
if (c[x][1]) isroot[c[x][1]]=1;
c[x][1]=0;
int u;
while (pre[x])
	{u=pre[x];
	splay(u);
	if (c[u][1]) isroot[c[u][1]]=1;
	c[u][1]=x;
	isroot[x]=0;
	splay(x);
	}
}
void evert(int x)
{access(x);
splay(x);
mark(x);
}
void cut(int x,int y)
{access(x);
splay(x);
int fa;
update(x);
fa=c[x][0];
while (c[fa][1]) 
	{update(fa);
	fa=c[fa][1];
	}
if (fa==y) swap(x,y);
access(y);
splay(y);
if (c[y][0]) 
	{isroot[c[y][0]]=1;
	pre[c[y][0]]=pre[y];
	}
c[y][0]=0;
}
void join(int y,int x)
{evert(x);
access(x);
splay(x);
pre[x]=y;
//access(x);
}
int getroot(int x)
{access(x);
splay(x);
while (c[x][0]) 
	{update(x);
	x=c[x][0];
	}
splay(x);
return x;
}
void work(int x,int y)
{int rx=getroot(x),ry=getroot(y);
if (rx==ry) printf("Yes\n"); else printf("No\n");
}
int main()
{freopen("cave.in","r",stdin);
//freopen("cave.out","w",stdout);
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++)
	{isroot[i]=1;
	c[i][1]=c[i][0]=pre[i]=rev[i]=0;
	}
for (i=1;i<=m;i++)
	{scanf("%s%d%d",&com,&u,&v);
	if (com[0]=='C') join(u,v);
	if (com[0]=='D') cut(u,v);
	if (com[0]=='Q') work(u,v);
//	for (int j=1;j<=n;j++)
//		printf("%d*%d %d %d %d %d %d\n",i,j,pre[j],c[j][0],c[j][1],rev[j],isroot[j]);
	}
fclose(stdin);
//fclose(stdout);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值