【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=2049
【题意】
给定森林,可能有连边或断边的操作,回答若干个连通性的询问。
【思路】
Link-Cut-Tree。
LCT的性质:
1. 有一条重链上的所有节点构成的splay称作这条链的辅助树。
2. 每个点的键值为这个点的深度。
3. 链的辅助树的根的父亲指向链顶的父亲,然而链顶父亲的儿子并不指向链的辅助树的根。
(我会告诉你上面是抄的Popoqqq大爷的PPT么
LCT的操作:
Access:切断原来的重儿子,将结点到原树根的路径变为重路径。先splay到辅助树的根,然后修改右儿子,只用修改ch[1],右儿子的fa不用改变。
Evert:将u旋转至原树的根,因为执行完Access之后u只是辅助树的根,所以还需要splay至原树根。维护2性质,通过旋转之后u到根的路径反转,需要打上反转标记。
Link:连接两个不相连的节点。将u旋转至原树的根,然后将u的fa设为v。注意这里的操作并不是合并splay而只是连接两棵辅助树。
Cut:断开两个节点。将u旋转至跟,然后Access(v),splay(v),这时候u一定处于v的左子树,直接切断就行了。
【代码】
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<iostream> 5 using namespace std; 6 7 const int N = 1e5+10; 8 9 struct Node { 10 Node *ch[2],*fa; 11 int rev; 12 Node() ; 13 void reverse() { 14 rev^=1; 15 swap(ch[0],ch[1]); 16 } 17 void up_push() { 18 if(fa->ch[0]==this||fa->ch[1]==this) 19 fa->up_push(); 20 if(rev) { 21 ch[0]->reverse(); 22 ch[1]->reverse(); 23 rev=0; 24 } 25 } 26 void maintain() { 27 } 28 }; 29 Node *null=new Node,T[N]; 30 Node::Node() { fa=ch[0]=ch[1]=null; rev=0; } 31 32 void rot(Node* o,int d) { //将o点向上旋转,方向为d^1 33 Node *p=o->fa; 34 p->ch[d]=o->ch[d^1]; 35 o->ch[d^1]->fa=p; 36 o->ch[d^1]=p; 37 o->fa=p->fa; 38 if(p==p->fa->ch[0]) 39 p->fa->ch[0]=o; 40 else if(p==p->fa->ch[1]) 41 p->fa->ch[1]=o; 42 p->fa=o; 43 p->maintain(); 44 } 45 void splay(Node* o) { //自下向上旋转至[所属splay]的根 46 o->up_push(); 47 Node *nf,*nff; 48 while(o->fa->ch[0]==o||o->fa->ch[1]==o) { //判断是否是根 49 nf=o->fa,nff=nf->fa; 50 if(o==nf->ch[0]) { 51 if(nf==nff->ch[0]) rot(nf,0); 52 rot(o,0); 53 } else { 54 if(nf==nff->ch[1]) rot(nf,1); 55 rot(o,1); 56 } 57 } 58 o->maintain(); 59 } 60 void Access(Node* o) { 61 Node* son=null; 62 while(o!=null) { //将o到根的路径变为重路径即合并到一棵splay 63 splay(o); 64 o->ch[1]=son; 65 o->maintain(); 66 son=o; o=o->fa; 67 } 68 } 69 void evert(Node* o) { //将o转到[整棵动态树]的根 70 Access(o); 71 splay(o); 72 o->reverse(); 73 } 74 void Link(Node* u,Node* v) { 75 evert(u); 76 u->fa=v; //辅助树的根指向链顶的父亲然而链顶的父亲并不指向根 77 } 78 void Cut(Node* u,Node* v) { 79 evert(u); 80 Access(v),splay(v); 81 v->ch[0]=u->fa=null; 82 v->maintain(); 83 } 84 85 int n,m; 86 87 void query(Node* u,Node* v) 88 { 89 Access(u),splay(u); 90 while(v->fa!=null) v=v->fa; 91 if(u==v) puts("Yes"); 92 else puts("No"); 93 } 94 95 int main() 96 { 97 // freopen("in.in","r",stdin); 98 // freopen("out.out","w",stdout); 99 null->fa=null->ch[0]=null->ch[1]=null; 100 char op[20]; int u,v; 101 scanf("%d%d",&n,&m); 102 while(m--) { 103 scanf("%s%d%d",&op,&u,&v); 104 if(op[0]=='Q') 105 query(&T[u],&T[v]); 106 else if(op[0]=='C') 107 Link(&T[u],&T[v]); 108 else 109 Cut(&T[u],&T[v]); 110 } 111 return 0; 112 }