BZOJ 2049: [Sdoi2008]Cave 洞穴勘测——LCT

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2049

省选之前来切一道数据结构模板题。

题意

这是一道模板题

N个点,M次操作,每次加边/删边/询问两个点是否连通,保证每次操作之后仍然是一棵树。

N<=1e4,M<=2e5。

做法

裸的LCT。

需要支持查找一个点所在树的根,只要不断向上查找father就行了。

(fread就是快啊。

#include <bits/stdc++.h>
using namespace std;
const int MAXN=20005, MAXB=2e7;
char BUF[MAXB], *cp=BUF;
void rd(int &x){
	x=0;
	while(*cp<'0'||'9'<*cp) cp++;
	while('0'<=*cp&&*cp<='9') x=x*10+*cp-'0', cp++;
}
char rdc(){
	while(*cp<'A'||'Z'<*cp) cp++;
	return *cp;
}

int N, M, top;

struct Node{
	Node *ch[2], *fa;
	int re;
}nd[MAXN], *rt, *st[MAXN];

inline int isrt(Node *x){return !(x->fa->ch[0]==x||x->fa->ch[1]==x);}

void rot(Node *x){
	Node *y=x->fa, *z=y->fa;
	int l=y->ch[1]==x, r=!l;
	if(!isrt(y)) z->ch[z->ch[1]==y]=x;
	x->ch[r]->fa=y; y->fa=x; x->fa=z;
	y->ch[l]=x->ch[r]; x->ch[r]=y;
}

void down(Node *x){
	if(x->re){
		x->ch[0]->re^=1; x->ch[1]->re^=1;
		swap(x->ch[0], x->ch[1]); x->re=0;
	}
}

void splay(Node *x){
	st[top++]=x;
	for(Node *i=x; !isrt(i); i=i->fa) st[top++]=i->fa;
	for(;top;--top) down(st[top-1]);
	while(!isrt(x)){
		Node *y=x->fa, *z=y->fa;
		if(!isrt(y)) rot((z->ch[1]==y)^(y->ch[1]==x)?x:y);
		rot(x);
	}
}

inline void access(Node *x){
	for(Node *i=nd; x!=nd; i=x,x=x->fa)
		splay(x), x->ch[1]=i;
}

inline void mkrt(Node *x){access(x),splay(x),x->re^=1;}

inline Node *getrt(Node *x){while(x->fa!=nd)x=x->fa; return x;}

inline void lin(Node *x, Node *y){mkrt(x); x->fa=y;}

inline void cut(Node *x, Node *y){
	mkrt(x); access(y); splay(y);
	y->ch[0]=x->fa=nd;
}

int main(){
	fread(BUF, 1, MAXB, stdin);
	rd(N),rd(M);
	for(int i=0; i<=N; ++i) nd[i].ch[0]=nd[i].ch[1]=nd[i].fa=nd;
	for(int i=0,u,v; i<M; ++i){
		char ch=rdc(); rd(u), rd(v);
		if(ch=='Q') puts(getrt(nd+u)==getrt(nd+v)?"Yes":"No");
		else if(ch=='C') lin(nd+u,nd+v);
		else cut(nd+u,nd+v);
	}
	return 0;
}
posted @ 2017-04-06 20:17  will7101  阅读(161)  评论(0编辑  收藏