题目链接:
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上