洛谷 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 }