BZOJ2049 洞穴勘测
? 解题记录 ? ? BZOJ ? ? LCT ?    2017-07-24 22:49:30    205    0    0

2049: [Sdoi2008]Cave 洞穴勘测


Description

辉辉热衷于洞穴勘测。某天,他按照地图来到了一片被标记为JSZX的洞穴群地区。经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连接了恰好两个洞穴。假如两个洞穴可以通过一条或者多条通道按一定顺序连接起来,那么这两个洞穴就是连通的,按顺序连接在一起的这些通道则被称之为这两个洞穴之间的一条路径。洞穴都十分坚固无法破坏,然而通道不太稳定,时常因为外界影响而发生改变,比如,根据有关仪器的监测结果,123号洞穴和127号洞穴之间有时会出现一条通道,有时这条通道又会因为某种稀奇古怪的原因被毁。辉辉有一台监测仪器可以实时将通道的每一次改变状况在辉辉手边的终端机上显示:如果监测到洞穴u和洞穴v之间出现了一条通道,终端机上会显示一条指令 Connect u v 如果监测到洞穴u和洞穴v之间的通道被毁,终端机上会显示一条指令 Destroy u v 经过长期的艰苦卓绝的手工推算,辉辉发现一个奇怪的现象:无论通道怎么改变,任意时刻任意两个洞穴之间至多只有一条路径。因而,辉辉坚信这是由于某种本质规律的支配导致的。因而,辉辉更加夜以继日地坚守在终端机之前,试图通过通道的改变情况来研究这条本质规律。然而,终于有一天,辉辉在堆积成山的演算纸中崩溃了……他把终端机往地面一砸(终端机也足够坚固无法破坏),转而求助于你,说道:“你老兄把这程序写写吧”。辉辉希望能随时通过终端机发出指令 Query u v,向监测仪询问此时洞穴u和洞穴v是否连通。现在你要为他编写程序回答每一次询问。已知在第一条指令显示之前,JSZX洞穴群中没有任何通道存在。

Input

第一行为两个正整数n和m,分别表示洞穴的个数和终端机上出现过的指令的个数。以下m行,依次表示终端机上出现的各条指令。每行开头是一个表示指令种类的字符串s("Connect”、”Destroy”或者”Query”,区分大小写),之后有两个整数u和v (1≤u, v≤n且u≠v) 分别表示两个洞穴的编号。

Output

对每个Query指令,输出洞穴u和洞穴v是否互相连通:是输出”Yes”,否则输出”No”。(不含双引号)

Sample Input

样例输入1 cave.in
200 5
Query 123 127
Connect 123 127
Query 123 127
Destroy 127 123
Query 123 127
样例输入2 cave.in

3 5
Connect 1 2
Connect 3 1
Query 2 3
Destroy 1 3
Query 2 3



Sample Output

样例输出1 cave.out
No
Yes
No


样例输出2 cave.out

Yes
No
 
 

        一道简单的裸的LCT模板,虽说是模板,还是交了4次,第一棵LCT。

        pushdown巨坑!rotate神坑!果真是细节决定成败

#include<cstdio>
#include<cstring>
#include<algorithm>
#define L 0
#define R 1
#define isroot(x) (tree[tree[x].fa].ch[L]!=x && tree[tree[x].fa].ch[R]!=x)
using namespace std;
const int maxn = 1e4+100;
int n, m;
struct node {
	int ch[2], fa;
	bool rv;
}tree[maxn];
void push_down(int rt) {
	if(tree[rt].rv) {
		tree[tree[rt].ch[L]].rv ^= 1;
		tree[tree[rt].ch[R]].rv ^= 1;
		tree[rt].rv = 0;
		swap(tree[rt].ch[L], tree[rt].ch[R]);
	}
}
void rotate(int rt) {
	int p = tree[rt].fa, a = tree[p].fa;
	int v = tree[p].ch[R] == rt;
	if(!isroot(p)) tree[a].ch[tree[a].ch[R] == p] = rt;/*1E9分坑爹的操作*/
	tree[p].ch[v] = tree[rt].ch[v^1], tree[tree[p].ch[v]].fa = p;
	tree[rt].ch[v^1] = p, tree[p].fa = rt, tree[rt].fa = a;
	
}

void splay(int rt, int y){
	int des = tree[y].fa;
	while(tree[rt].fa != des){
		int p = tree[rt].fa, a = tree[p].fa;
		push_down(a), push_down(p), push_down(rt);
		if(p != y)
			if((tree[a].ch[R] == p) ^ (tree[p].ch[R] == rt))	rotate(rt);
			else rotate(p);
		rotate(rt);
	}
}
void change(int rt, int ch){
	int u = rt;
	while(!isroot(u)) 
		u = tree[u].fa;
	splay(rt, u), push_down(rt);/*十分坑爹  可能原来就在根节点*/ 
	tree[rt].ch[R] = ch;
}
int access(int rt){
	for(change(rt, 0); tree[rt].fa; rt = tree[rt].fa) change(tree[rt].fa, rt);
	int u = rt;
	while(push_down(u), tree[u].ch[L])	 u = tree[u].ch[L];/*重要的事情说三遍 push push push……*/
	return splay(u, rt), u;/*把原树根转到splay的根节点以便于link操作*/
}

/*由于access 最后把树根splay到了平衡树的根  可以直接进行连接*/
#define link(a, b) tree[b = access(b)].rv ^= 1, tree[b].fa = a;
#define cut(a, b) change(a, 0), change(b, 0), tree[a].fa == b ? tree[a].fa = 0 : tree[b].fa = 0;
#define connect(a, b) (access(a) == access(b))

int main(){
	scanf("%d%d", &n, &m);
	while(m--) {
		char opt[20];
		int a, b;
		scanf("%s", opt);
		scanf("%d%d", &a, &b);
		if(opt[0] == 'Q') 
			printf("%s\n", connect(a, b) ? "Yes" : "No");
		if(opt[0] == 'D') cut(a, b);
		if(opt[0] == 'C') link(a, b);
	}
	return 0;
}

+++++--2018/1/25新版--+++++

#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
const int maxn = 1e5 + 5;
char s;
int n, m, a, b, cnt;
inline char gc(){
    static char buf[2000000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 2000000, stdin), p1 == p2) ? EOF : *p1++;
}
inline void read(int & x) {
    x = 0; static char c = gc();
    while(!isdigit(c)) c = gc();
    while(isdigit(c)) x = x * 10 + c - '0', c = gc();
}
inline void rc(char & x) {
    x = gc();
    while(x != 'Q' && x != 'C' && x != 'D') x = gc();
}
inline void out(bool t) {
	if(t) putchar('Y'), putchar('e'), putchar('s');
	else putchar('N'), putchar('o');
	putchar('\n');
}
namespace LCT {
	const int L = 0, R = 1;
	struct node {
		int ch[2], fa, rv;
	}tree[maxn];
	#define isrt(x) (tree[tree[x].fa].ch[R] != x && tree[tree[x].fa].ch[L] != x)
	void push_down(int rt) {
		if(tree[rt].rv) {
			tree[rt].rv = 0;
			swap(tree[rt].ch[L], tree[rt].ch[R]);
			tree[tree[rt].ch[L]].rv ^= 1;
			tree[tree[rt].ch[R]].rv ^= 1;
		}
	}
	void rotate(int rt) {
		int p = tree[rt].fa, a = tree[p].fa;
		int r = tree[p].ch[R] == rt, l = r ^ 1;
		if(!isrt(p)) tree[a].ch[tree[a].ch[R] == p] = rt;
		tree[rt].fa = a, tree[p].fa = rt, tree[tree[rt].ch[l]].fa = p;
		tree[p].ch[r] = tree[rt].ch[l], tree[rt].ch[l] = p;
	}
	void splay(int rt, int y) {
		int des = tree[y].fa;
		while(tree[rt].fa != des) {
			int p = tree[rt].fa, a = tree[p].fa;
			push_down(a), push_down(p), push_down(rt);
			if(p != y)  if((tree[a].ch[R] == p) ^ (tree[p].ch[R] == rt)) rotate(rt);
					   	  else rotate(p);
			rotate(rt);
		}
	}
	int findrt(int x) {while(!isrt(x))x = tree[x].fa;return x;}
	void change(const int &x, const int &y) {
		int u = findrt(x);
		splay(x, u), /*!!!*/push_down(x),/*!!!*/ tree[x].ch[R] = y;
	}
	int access(int x) {
		for(change(x, 0); tree[x].fa; x = tree[x].fa) 
			change(tree[x].fa, x);
		int u = x;
		/*!!!*/while(push_down(x), tree[x].ch[L]) x = tree[x].ch[L];/*!!!*/
		return splay(x, u), x;
	}
	void link(int x, int y) {tree[x = access(x)].rv ^= 1, tree[x].fa = y;}
	void cut(int x, int y) {change(x, 0), change(y, 0), tree[tree[x].fa == y ? x : y].fa = 0;}
	bool isconnect(int x, int y) {return access(x) == access(y);}
}

int main() {
	read(n), read(m);
	for(register int i = 1; i <= m; ++i) {
		rc(s), read(a), read(b);
		if(s == 'Q') out(LCT::isconnect(a, b));
		else if(s == 'C') LCT::link(a, b);
		else LCT::cut(a, b);
	}
	return 0;
}

 

上一篇: 洛谷P1018 乘积最大

下一篇: 洛谷 P2812 校园网络

205 人读过
立即登录, 发表评论.
没有帐号? 立即注册
0 条评论
文档导航