洛谷 P3690 【模板】Link Cut Tree (动态树) || bzoj 3282: Tree

https://blog.csdn.net/saramanda/article/details/55253627

https://blog.csdn.net/CHHNZ/article/details/55504875

lct模板

  1 #include<cstdio>
  2 #include<algorithm>
  3 using namespace std;
  4 namespace LCT
  5 {
  6 struct Node
  7 {
  8     Node *ch[2],*fa;
  9     bool rev;
 10     int dat,xorx;
 11 }nodes[300100];
 12 int mem;
 13 Node *getnode()
 14 {
 15     return nodes+(mem++);
 16 }
 17 bool isroot(Node *x)
 18 {
 19     return (!x->fa)||((x->fa->ch[0]!=x)&&(x->fa->ch[1]!=x));
 20 }
 21 void upd(Node *x)
 22 {
 23     x->xorx=(x->ch[0]?x->ch[0]->xorx:0)^(x->ch[1]?x->ch[1]->xorx:0)^x->dat;
 24 }
 25 void pd(Node *x)
 26 {
 27     if(x->rev)
 28     {
 29         swap(x->ch[0],x->ch[1]);
 30         if(x->ch[0])    x->ch[0]->rev^=1;
 31         if(x->ch[1])    x->ch[1]->rev^=1;
 32         x->rev=0;
 33     }
 34 }
 35 bool gson(Node *o)    {return o==o->fa->ch[1];}//获得是父亲的左儿子(返回0)还是右儿子(1),要求保证存在父亲
 36 void rotate(Node *o,bool d)
 37 //在o子树中执行d=0左旋,d=1右旋,在旋转前不标记下传,并将o父节点的对应子节点由o变为需要值,要求保证存在子树(!d)
 38 {
 39     Node *k=o->ch[!d];if(!isroot(o))    o->fa->ch[gson(o)]=k;//注意这一句修改o父节点的要写在前面,曾经出过错调了一会
 40     o->ch[!d]=k->ch[d];k->ch[d]=o;
 41     upd(o);upd(k);
 42     k->fa=o->fa;o->fa=k;if(o->ch[!d])    o->ch[!d]->fa=o;
 43 }
 44 Node *st[300100];int top;
 45 void solvetag(Node *o)
 46 {
 47     while(!isroot(o))    st[++top]=o,o=o->fa;
 48     st[++top]=o;
 49     while(top)    pd(st[top--]);
 50 }
 51 void splay(Node *o)
 52 {
 53     solvetag(o);
 54     Node *fa,*fafa;bool d1,d2;
 55     while(!isroot(o))
 56     {
 57         fa=o->fa;d1=(o==fa->ch[0]);
 58         if(isroot(fa))    rotate(fa,d1);
 59         else
 60         {
 61             fafa=o->fa->fa;d2=(fa==fafa->ch[0]);//要保证fa不是root之后才能获取这两个值,曾错过
 62             if(d1==d2)    rotate(fafa,d1),rotate(fa,d1);//zig-zig,两次相同方向的单旋,先把父亲转上去,再把自己转上去
 63             else    rotate(fa,d1),rotate(fafa,d2);//zig-zag,两次相反方向的单旋,连续两次把自己转上去
 64         }
 65     }
 66 }
 67 void access(Node *o)
 68 {
 69     for(Node *lst=NULL;o;lst=o,o=o->fa)
 70     {
 71         splay(o);//此处不pushdown是由于splay中保证进行过了
 72         o->ch[1]=lst;upd(o);//注意upd
 73     }
 74 }
 75 Node *gtop(Node *o)
 76 {
 77     access(o);splay(o);
 78     for(;o->ch[0];o=o->ch[0],pd(o));//此处不在开始前pushdown(o)是由于splay中保证进行过了
 79     splay(o);return o;//听说这里不splay一下也很难卡掉
 80 }
 81 void mtop(Node *o)    {access(o);splay(o);o->rev^=1;}
 82 void link(Node *x,Node *y)
 83 {
 84     if(gtop(x)==gtop(y))    return;
 85     mtop(y);y->fa=x;
 86 }
 87 void cut(Node *x,Node *y)
 88 {
 89     mtop(x);access(y);splay(y);
 90     if(y->ch[0]!=x||x->ch[1])    return;//如果x、y之间直接有边,那么上面一行的操作之后应当是x与y在单独一棵splay中,那么一定保证y左子节点是x且x没有右子节点
 91     x->fa=y->ch[0]=NULL;//注意,改的是x的父亲和y的子节点(虽然x的确是树的根,但是此时在splay上是y的子节点,不能搞混)
 92     upd(y);//注意
 93 }
 94 int query(Node *x,Node *y)
 95 {
 96     mtop(x);access(y);splay(y);
 97     //if(gtop(y)!=x)    return 0;//此题保证x与y连通,不需要
 98     return y->xorx;
 99 }
100 }
101 LCT::Node *nd[300100];
102 int n,m;
103 int main()
104 {
105     int i,idx,x,y;
106     scanf("%d%d",&n,&m);
107     for(i=1;i<=n;i++)
108     {
109         nd[i]=LCT::getnode();
110         scanf("%d",&nd[i]->dat);nd[i]->xorx=nd[i]->dat;//注意改xorx
111     }
112     for(i=1;i<=m;i++)
113     {
114         scanf("%d%d%d",&idx,&x,&y);
115         if(idx==0)    printf("%d\n",LCT::query(nd[x],nd[y]));
116         else if(idx==1)    LCT::link(nd[x],nd[y]);
117         else if(idx==2)    LCT::cut(nd[x],nd[y]);
118         else if(idx==3)    LCT::splay(nd[x]),nd[x]->dat=y,LCT::upd(nd[x]);
119         //可能是由于题面和数据的一些奥妙重重的原因,此题即使不splay(nd[x])也可以A掉,但是splay到根之后却能保证改变该点权值只会影响自身的xorx
120     }
121     return 0;
122 }

 

posted @ 2018-04-17 08:12  hehe_54321  阅读(188)  评论(0编辑  收藏  举报
AmazingCounters.com