BZOJ 2049: [Sdoi2008]Cave 洞穴勘測 LCT
入门级LCT: 仅仅有 Cut Link
2049: [Sdoi2008]Cave 洞穴勘測
Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 3073 Solved: 1379
[Submit][Status]
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
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
No
Yes
No
例子输出2 cave.out
Yes
No
HINT
数据说明 10%的数据满足n≤1000, m≤20000 20%的数据满足n≤2000, m≤40000 30%的数据满足n≤3000, m≤60000 40%的数据满足n≤4000, m≤80000 50%的数据满足n≤5000, m≤100000 60%的数据满足n≤6000, m≤120000 70%的数据满足n≤7000, m≤140000 80%的数据满足n≤8000, m≤160000 90%的数据满足n≤9000, m≤180000 100%的数据满足n≤10000, m≤200000 保证全部Destroy指令将摧毁的是一条存在的通道本题输入、输出规模比較大。建议c\c++选手使用scanf和printf进行I\O操作以免超时
Source
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn=11000; int ch[maxn][2],pre[maxn]; int rev[maxn]; bool rt[maxn]; void update_rev(int r) { if(!r) return ; swap(ch[r][0],ch[r][1]); rev[r]^=1; } void push_down(int r) { if(rev[r]) { update_rev(ch[r][0]); update_rev(ch[r][1]); rev[r]=0; } } void Rotate(int x) { int y=pre[x],kind=ch[y][1]==x; ch[y][kind]=ch[x][!kind]; pre[ch[y][kind]]=y; pre[x]=pre[y]; pre[y]=x; ch[x][!kind]=y; if(rt[y]) rt[y]=false,rt[x]=true; else ch[pre[x]][ch[pre[x]][1]==y]=x; } void P(int r) { if(!rt[r]) P(pre[r]); push_down(r); } void Splay(int r) { P(r); while(!rt[r]) { int f=pre[r],ff=pre[f]; if(rt[f]) Rotate(r); else if((ch[ff][1]==f)==(ch[f][1]==r)) Rotate(f),Rotate(r); else Rotate(r),Rotate(r); } } int Access(int x) { int y=0; for(;x;x=pre[y=x]) { Splay(x); rt[ch[x][1]]=true,rt[ch[x][1]=y]=false; } return y; } bool judge(int u,int v) { while(pre[u]) u=pre[u]; while(pre[v]) v=pre[v]; return u==v; } void mroot(int r) { Access(r); Splay(r); update_rev(r); } void link(int u,int v) { mroot(u); pre[u]=v; } void cut(int u,int v) { mroot(u); Splay(v); pre[ch[v][0]]=pre[v]; pre[v]=0; rt[ch[v][0]]=true; ch[v][0]=0; } char op[50]; int n,m; void init() { memset(pre,0,sizeof(pre)); memset(ch,0,sizeof(ch)); memset(rev,0,sizeof(rev)); memset(rt,true,sizeof(rt)); } int main() { while(scanf("%d%d",&n,&m)!=EOF) { init(); while(m--) { scanf("%s",op); int u,v; scanf("%d%d",&u,&v); if(op[0]=='C') link(u,v); else if(op[0]=='D') cut(u,v); else { if(judge(u,v)==true) puts("Yes"); else puts("No"); } } } return 0; }