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 }
lct模板

有一个小细节: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 }
AC代码

例题:

洞穴勘测  魔法森林  弹飞绵羊  [ZJOI2012]网络   Tree II(LONG_MAX0.5 == 46341)

水管局长  温暖会指引我们前行  染色   长跑   大融合  在美妙的数学王国中畅游

假装搞完了LCT...总结一波。

不要忘了pushup,rotate别写错。可以维护连通性,生成树,边双,子树信息。可以链修改。

这才是基础模型...神仙题我都做不来...

posted @ 2018-12-20 17:53  huyufeifei  阅读(...)  评论(...编辑  收藏