lct
嗯,重新写了个模板出来。
1 #include <cstdio> 2 #include <algorithm> 3 4 const int N = 300010; 5 6 int fa[N], s[N][2], val[N], sum[N], S[N], Sp; 7 bool rev[N]; 8 9 inline bool no_root(int x) { 10 return (s[fa[x]][0] == x) || (s[fa[x]][1] == x); 11 } 12 13 inline void pushup(int x) { 14 sum[x] = val[x] ^ sum[s[x][0]] ^ sum[s[x][1]]; 15 return; 16 } 17 18 inline void pushdown(int x) { 19 if(rev[x]) { 20 if(s[x][0]) { 21 rev[s[x][0]] ^= 1; 22 } 23 if(s[x][1]) { 24 rev[s[x][1]] ^= 1; 25 } 26 std::swap(s[x][0], s[x][1]); 27 rev[x] = 0; 28 } 29 return; 30 } 31 32 inline void rotate(int x) { 33 int y = fa[x]; 34 int z = fa[y]; 35 bool f = (s[y][1] == x); 36 37 fa[x] = z; 38 if(no_root(y)) { 39 s[z][s[z][1] == y] = x; 40 } 41 s[y][f] = s[x][!f]; 42 if(s[x][!f]) { 43 fa[s[x][!f]] = y; 44 } 45 s[x][!f] = y; 46 fa[y] = x; 47 48 pushup(y); 49 pushup(x); 50 return; 51 } 52 53 inline void splay(int x) { 54 int y = x; 55 S[++Sp] = y; 56 while(no_root(y)) { 57 y = fa[y]; 58 S[++Sp] = y; 59 } 60 while(Sp) { 61 pushdown(S[Sp]); 62 Sp--; 63 } 64 65 y = fa[x]; 66 int z = fa[y]; 67 while(no_root(x)) { 68 if(no_root(y)) { 69 (s[z][1] == y) ^ (s[y][1] == x) ? 70 rotate(x) : rotate(y); 71 } 72 rotate(x); 73 y = fa[x]; 74 z = fa[y]; 75 } 76 return; 77 } 78 79 inline void access(int x) { 80 int y = 0; 81 while(x) { 82 splay(x); 83 s[x][1] = y; 84 /*if(y) { 85 fa[y] = x; // no need change fa[y] 86 }*/ 87 pushup(x); 88 y = x; 89 x = fa[x]; 90 } 91 return; 92 } 93 94 inline void make_root(int x) { 95 access(x); 96 splay(x); 97 rev[x] ^= 1; 98 return; 99 } 100 101 inline int find_root(int x) { 102 access(x); 103 splay(x); 104 while(s[x][0]) { 105 x = s[x][0]; 106 pushdown(x); // important 107 } 108 return x; 109 } 110 111 inline void link(int x, int y) { 112 make_root(x); 113 if(find_root(y) != x) { // cannot change y 114 fa[x] = y; 115 } 116 return; 117 } 118 119 inline void cut(int x, int y) { 120 make_root(x); 121 access(y); 122 splay(y); 123 if(s[y][0] == x && fa[x] == y && !s[x][1]) { 124 fa[x] = s[y][0] = 0; 125 pushup(y); 126 } 127 return; 128 } 129 130 inline int ask(int x, int y) { 131 make_root(x); 132 access(y); 133 splay(y); 134 return sum[y]; 135 } 136 137 inline void change(int x, int c) { // only could change the value of root 138 splay(x); 139 val[x] = c; 140 pushup(x); 141 return; 142 } 143 144 int main() { 145 146 int n, m; 147 scanf("%d%d", &n, &m); 148 for(int i = 1; i <= n; i++) { 149 scanf("%d", &val[i]); 150 } 151 152 for(int i = 1, f, x, y; i <= m; i++) { 153 scanf("%d%d%d", &f, &x, &y); 154 if(!f) { 155 int t = ask(x, y); 156 printf("%d\n", t); 157 } 158 else if(f == 1) { 159 link(x, y); 160 } 161 else if(f == 2) { 162 cut(x, y); 163 } 164 else { 165 change(x, y); 166 } 167 } 168 169 return 0; 170 }
有一个小细节:findroot是很特殊的函数。一是它返回int,二是它最后最好加上一句splay(x)。有的题卡这个...
之前有个一直困扰我的问题:为什么不能在rotate内pushdown?现已解决。
问题出在这种语句上:
make_root(x);
access(x);
我们的目的是把x单独拿出来作为一颗splay,但是事实上发生了什么呢?
首先你在make_root中access(x)并把它旋到根打标记。此时它有个左儿子和一个标记。
然后我们看,如果我们access它,那么第一步是splay它,第二步剪断它的右儿子。
splay的时候,如果我们把pushdown放在rotate里面,那么就一次都不会被执行。在外面就会被执行。
然后如果没有执行的话,剪断右儿子就没剪掉,因为你右儿子还在左边。
解决方法是在access里面添加一个pushdown,之后实测AC。
1 #include <cstdio> 2 #include <algorithm> 3 4 const int N = 300010; 5 6 int fa[N], s[N][2], val[N], sum[N], S[N], Sp; 7 bool rev[N]; 8 9 inline bool no_root(int x) { 10 return (s[fa[x]][0] == x) || (s[fa[x]][1] == x); 11 } 12 13 inline void pushup(int x) { 14 sum[x] = val[x] ^ sum[s[x][0]] ^ sum[s[x][1]]; 15 return; 16 } 17 18 inline void pushdown(int x) { 19 if(rev[x]) { 20 if(s[x][0]) { 21 rev[s[x][0]] ^= 1; 22 } 23 if(s[x][1]) { 24 rev[s[x][1]] ^= 1; 25 } 26 std::swap(s[x][0], s[x][1]); 27 rev[x] = 0; 28 } 29 return; 30 } 31 32 inline void rotate(int x) { 33 int y = fa[x]; 34 int z = fa[y]; 35 pushdown(y); 36 pushdown(x); 37 bool f = (s[y][1] == x); 38 39 fa[x] = z; 40 if(no_root(y)) { 41 s[z][s[z][1] == y] = x; 42 } 43 s[y][f] = s[x][!f]; 44 if(s[x][!f]) { 45 fa[s[x][!f]] = y; 46 } 47 s[x][!f] = y; 48 fa[y] = x; 49 50 pushup(y); 51 pushup(x); 52 return; 53 } 54 55 inline void splay(int x) { 56 /*int y = x; 57 S[++Sp] = y; 58 while(no_root(y)) { 59 y = fa[y]; 60 S[++Sp] = y; 61 } 62 while(Sp) { 63 pushdown(S[Sp]); 64 Sp--; 65 }*/ 66 67 int y = fa[x]; 68 int z = fa[y]; 69 while(no_root(x)) { 70 if(no_root(y)) { 71 (s[z][1] == y) ^ (s[y][1] == x) ? 72 rotate(x) : rotate(y); 73 } 74 rotate(x); 75 y = fa[x]; 76 z = fa[y]; 77 } 78 return; 79 } 80 81 inline void access(int x) { 82 int y = 0; 83 while(x) { 84 splay(x); 85 pushdown(x); 86 s[x][1] = y; // no need change fa[y] 87 pushup(x); 88 y = x; 89 x = fa[x]; 90 } 91 return; 92 } 93 94 inline void make_root(int x) { 95 access(x); 96 splay(x); 97 rev[x] ^= 1; 98 return; 99 } 100 101 inline int find_root(int x) { 102 access(x); 103 splay(x); 104 while(s[x][0]) { 105 x = s[x][0]; 106 pushdown(x); 107 } 108 return x; 109 } 110 111 inline void link(int x, int y) { 112 make_root(x); 113 if(find_root(y) != x) { // cannot change y 114 fa[x] = y; 115 } 116 return; 117 } 118 119 inline void cut(int x, int y) { 120 make_root(x); 121 access(y); 122 splay(y); 123 if(s[y][0] == x && fa[x] == y && !s[x][1]) { 124 fa[x] = s[y][0] = 0; 125 pushup(y); 126 } 127 return; 128 } 129 130 inline int ask(int x, int y) { 131 make_root(x); 132 access(y); 133 splay(y); 134 return sum[y]; 135 } 136 137 inline void change(int x, int c) { // change must in root 138 make_root(x); 139 val[x] = c; 140 pushup(x); 141 return; 142 } 143 144 int main() { 145 146 int n, m; 147 scanf("%d%d", &n, &m); 148 for(int i = 1; i <= n; i++) { 149 scanf("%d", &val[i]); 150 } 151 for(int i = 1, f, x, y; i <= m; i++) { 152 scanf("%d%d%d", &f, &x, &y); 153 if(!f) { 154 int t = ask(x, y); 155 printf("%d\n", t); 156 } 157 else if(f == 1) { 158 link(x, y); 159 } 160 else if(f == 2) { 161 cut(x, y); 162 } 163 else { 164 change(x, y); 165 } 166 } 167 168 return 0; 169 }
例题:
洞穴勘测 魔法森林 弹飞绵羊 [ZJOI2012]网络 Tree II(LONG_MAX0.5 == 46341)
水管局长 温暖会指引我们前行 染色 长跑 大融合 在美妙的数学王国中畅游
假装搞完了LCT...总结一波。
不要忘了pushup,rotate别写错。可以维护连通性,生成树,边双,子树信息。可以链修改。
这才是基础模型...神仙题我都做不来...