LCT模板

题目链接:

 
lct一开始本没有splay 是在access的时候现建的 所以一开始每个点仅存了fa
 
  1 #include <cstdio>
  2 #include <algorithm>
  3 using namespace std;
  4 const int N = 3e5 + 5;
  5 int n, m;
  6 struct Splay{
  7     int ch[2], fa, w, rev, sum;
  8 }spl[N]; 
  9 int s[N];
 10 
 11 inline bool get(int x){
 12     return x == spl[spl[x].fa].ch[1];
 13 }
 14 
 15 inline void update(int x){
 16     spl[x].sum = spl[x].w ^ spl[spl[x].ch[0]].sum ^ spl[spl[x].ch[1]].sum;
 17 }//统计抑或和 
 18 
 19 inline void pushdown(int x){
 20     if(!spl[x].rev) return ;
 21     int &ls = spl[x].ch[0], &rs = spl[x].ch[1];
 22     swap(ls, rs);
 23     spl[ls].rev ^= 1;
 24     spl[rs].rev ^= 1;
 25     spl[x].rev ^= 1;
 26 }
 27 
 28 inline bool is_root(int x){
 29     return spl[spl[x].fa].ch[0] != x && spl[spl[x].fa].ch[1] != x; 
 30 }
 31 //注意这里不只有一颗splay 所以根节点不一定是0 
 32  
 33 inline void rotate(int x){
 34     int y = spl[x].fa, z = spl[y].fa;
 35     bool k = get(x);
 36     if(!is_root(y)) spl[z].ch[get(y)] = x;
 37     spl[x].fa = z;
 38     spl[spl[x].ch[k ^ 1]].fa = y; spl[y].ch[k] = spl[x].ch[k ^ 1];
 39     spl[y].fa = x; spl[x].ch[k ^ 1] = y;
 40     update(y); update(x);
 42 }
//日常rotate
43 44 void splay(int x){ 45 int top = 0; 46 s[++top] = x; 47 for(int i = x; !is_root(i); i = spl[i].fa) 48 s[++top] = spl[i].fa; 49 while(top > 0) 50 pushdown(s[top--]); 51 for(int f; !is_root(x); rotate(x)) 52 if(!is_root(f = spl[x].fa)) 53 rotate(get(x) == get(f) ? f : x); 54 } 55
/*
注意这里除了平时的splay操作还要先把翻转标记下推
*/ 56 void access(int x){ 57 for(int i = 0; x; i = x, x = spl[x].fa){ 58 splay(x); 59 spl[x].ch[1] = i; 60 update(x); 61 } 62 }
/*
打通一条从根到x的路径 并为这条路径建上splay
*/
63 64 void evert(int x){ 65 access(x); 66 splay(x); 67 spl[x].rev ^= 1; 68 }
/*
将x变成原树树根
*/
69 70 int find(int x){ 71 access(x); 72 splay(x); 73 while(spl[x].ch[0]) 74 x = spl[x].ch[0]; 75 return x; 76 }
/*
找到原树树根
*/
77 78 void link(int x, int y){ 79 evert(x); 80 spl[x].fa = y; 81 }
/*
连一条x y之间的边
*/
82 83 void cut(int x, int y){ 84 evert(x); 85 access(y); 86 splay(y); 87 if(spl[x].ch[1] || spl[x].fa != y || spl[y].ch[get(x) ^ 1]) return ; 89 spl[y].ch[0] = spl[x].fa = 0; 90 }
/*
切断x y之间的边(当然前提是它们之间有边
把x转为原树树根
打通到y的道路
若x y间有边 现在这个小splay长成这个样子

所以判断一下就好了……


*/
91 92 void change(int x, int y){ 93 spl[x].w = y; 94 access(x); 95 splay(x); 96 }
/*
修改一个点的信息
直接修改 然后做相关更新
*/
97 98 int query(int x, int y){ 99 evert(x); 100 access(y); 101 splay(y); 102 return spl[y].sum; 103 } 104
/*
查询路径上的抑或和
把x转为原树树根
打通到y的道路
现在x,y的路径就是整颗splay
因为当前splay中 x深度最小 y深度最大
所以 路径上点的信息 的统计 就是 整棵树的统计
返回 树根统计值 就可以了
(打了断句…
*/ 105 106 int main(){ 107 scanf("%d%d", &n, &m); 108 for(int i = 1; i <= n; i++) 109 scanf("%d", &spl[i].w); 110 while(m--){ 111 int op, x, y; 112 scanf("%d%d%d", &op, &x, &y); 113 switch(op){ 114 case 0: 115 printf("%d ", query(x, y)); 116 break; 117 case 1: 118 if(find(x) == find(y)) break; 119 link(x, y); 120 break; 121 case 2: 122 if(find(x) != find(y)) break; 123 cut(x, y); 124 break; 125 case 3: 126 change(x, y); 127 break; 128 } 129 } 130 return 0; 131 }

注意使用手写堆栈 stl会超时

相关题目 

裸题…弹飞的连到点n + 1上
原文地址:https://www.cnblogs.com/hjmmm/p/9271722.html