山东济南彤昌机械科技有限公司 山东济南江鹏工贸游有限公司

bzoj 2049 [Sdoi2008]Cave 洞穴勘测(LCT)

 

【题目链接】

 

    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 }

 

posted on 2016-03-25 13:55  hahalidaxin  阅读(203)  评论(0编辑  收藏  举报