bzoj2002: [Hnoi2010]Bounce 弹飞绵羊
lct入门题?只需要Link Cut,不需要换根和维护其他标记
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int N = 200000 + 10; 6 7 int ch[N][2], p[N], sz[N], tl[N]; 8 9 int n, m; 10 11 bool isroot(int x) { 12 return ch[p[x]][0] != x && ch[p[x]][1] != x; 13 } 14 #define l ch[x][0] 15 #define r ch[x][1] 16 void update(int x) { 17 assert(x != 0); 18 sz[x] = sz[l] + sz[r] + 1; 19 } 20 #undef l 21 #undef r 22 23 void rotate(int x) { 24 int y = p[x], z = p[y]; 25 int l = ch[y][1] == x, r = l ^ 1; 26 if(!isroot(y)) ch[z][ch[z][1] == y] = x; 27 p[ch[x][r]] = y; 28 p[y] = x; 29 p[x] = z; 30 31 ch[y][l] = ch[x][r]; 32 ch[x][r] = y; 33 34 update(y), update(x); 35 } 36 37 void splay(int x) { 38 while(!isroot(x)) { 39 int y = p[x], z = p[y]; 40 if(!isroot(y)) { 41 if((ch[y][1] == x) ^ (ch[z][1] == y)) rotate(x); 42 else rotate(y); 43 } 44 rotate(x); 45 } 46 } 47 48 void access(int x) { 49 for(int t = 0; x ; t = x, x = p[x]) { 50 splay(x), ch[x][1] = t, update(x); 51 } 52 } 53 54 int getroot(int x) { 55 for(access(x), splay(x); ch[x][0]; x = ch[x][0]); 56 return splay(x), x; 57 } 58 59 void Cut(int x) { 60 access(x), splay(x); 61 p[ch[x][0]] = 0, ch[x][0] = 0; 62 update(x); 63 } 64 65 void Link(int x, int y) { 66 Cut(x), p[x] = y; 67 } 68 69 int main() { 70 #ifdef DEBUG 71 freopen("in.txt", "r", stdin); 72 #endif 73 74 int n; scanf("%d", &n); 75 for(int i = 1; i <= n; i++) { 76 sz[i] = 1, scanf("%d", tl + i); 77 p[i] = min(tl[i] + i, n + 1); 78 tl[i] = p[i]; 79 } 80 sz[n + 1] = 1; 81 82 int m; scanf("%d", &m); 83 while(m--) { 84 int cmd, a, b; 85 scanf("%d%d", &cmd, &a), ++a; 86 if(cmd == 1) { 87 access(a), splay(a); 88 printf("%d\n", sz[a] - 1); 89 } else { 90 scanf("%d", &b); 91 int y = min(a + b, n + 1); 92 if(y != tl[a]) Link(a, tl[a] = y); 93 } 94 } 95 96 return 0; 97 }
分块也是可以的
每个点下一个维护跳出块的点是哪个,以及要用多少步。
sz取$\sqrt{2n}$比较合适。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int N = 200000 + 10; 6 7 int next[N], step[N], belong[N], fa[N]; 8 9 void modify(int x, int y) { 10 if(belong[x] != belong[y]) { 11 step[x] = 1, next[x] = y; 12 } else { 13 step[x] = step[y] + 1; 14 next[x] = next[y]; 15 } 16 } 17 18 int main() { 19 #ifdef DEBUG 20 freopen("in.txt", "r", stdin); 21 #endif 22 23 int n; scanf("%d", &n); 24 int bs = sqrt(n * 2) + 1; 25 for(int i = 0; i < n; i++) { 26 belong[i] = i / bs; 27 scanf("%d", fa + i); 28 fa[i] = min(fa[i] + i, n); 29 } 30 belong[n] = -1; 31 for(int i = n-1; i >= 0; i--) modify(i, min(n, fa[i])); 32 33 int m; scanf("%d", &m); 34 while(m--) { 35 int opt, x; 36 scanf("%d%d", &opt, &x); 37 if(opt == 1) { 38 int ans = 0; 39 while(x != n) { 40 ans += step[x]; 41 x = next[x]; 42 } 43 printf("%d\n", ans); 44 } else { 45 scanf("%d", fa + x); 46 fa[x] = min(fa[x] + x, n); 47 for(int i = x; i >= 0 && belong[i] == belong[x]; i--) { 48 modify(i, fa[i]); 49 } 50 } 51 } 52 53 return 0; 54 }
splay维护括号序列也是可以的。
第一次写splay维护括号序列,用了好多以前没用过的splay写法。
定位指针自底向上的splay知不知道根是谁简直无所谓,随便splay一个就成根了。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int N = 200000 + 10; 6 7 vector<int> G[N]; 8 int dfn[2][N], dfs_clock; 9 10 const int maxnode = 400000 + 10; 11 int ch[maxnode][2], p[maxnode], val[maxnode], sum[maxnode]; 12 13 void dfs(int u) { 14 val[dfn[0][u] = ++dfs_clock] = 1; 15 for(unsigned i = 0; i < G[u].size(); i++) { 16 dfs(G[u][i]); 17 } 18 val[dfn[1][u] = ++dfs_clock] = -1; 19 } 20 21 // splay 22 23 void update(int x) { 24 sum[x] = val[x]; 25 sum[x] += sum[ch[x][0]]; 26 sum[x] += sum[ch[x][1]]; 27 } 28 29 void rotate(int x) { 30 int y = p[x], z = p[y]; 31 if(z) ch[z][ch[z][1] == y] = x; 32 int l = ch[y][1] == x, r = l ^ 1; 33 p[x] = z, p[y] = x, p[ch[x][r]] = y; 34 ch[y][l] = ch[x][r], ch[x][r] = y; 35 update(y), update(x); 36 } 37 38 void splay(int x, int FA = 0) { 39 while(p[x] != FA) { 40 int y = p[x], z = p[y]; 41 if(z) { 42 if((ch[y][1] == x) ^ (ch[z][1] == y)) rotate(x); 43 else rotate(y); 44 } 45 rotate(x); 46 } 47 } 48 49 int tot = 0; 50 int build(int sz) { 51 if(sz <= 0) return 0; 52 int mid = sz >> 1; 53 int l = build(mid), 54 x = ++tot, 55 r = build(sz - mid - 1); 56 ch[x][0] = l, ch[x][1] = r; 57 p[l] = x, p[r] = x, update(x); 58 return x; 59 } 60 61 int get_pre(int x) { 62 splay(x), x = ch[x][0]; 63 while(ch[x][1]) x = ch[x][1]; 64 return splay(x), x; 65 } 66 67 int get_suf(int x) { 68 splay(x), x = ch[x][1]; 69 while(ch[x][0]) x = ch[x][0]; 70 return splay(x), x; 71 } 72 73 int split(int x) { //将x作为左边的最后一个元素分裂 74 splay(x); 75 int y = ch[x][1]; 76 ch[x][1] = 0, p[y] = 0, update(x); 77 return y; 78 } 79 80 bool iot(int x, int y) { 81 splay(x), splay(y); 82 if(p[x]) return 1; 83 return 0; 84 } 85 86 void merge(int x, int y) { //将x所在的子树与y所在的子树合并 87 splay(x), splay(y); 88 while(ch[x][1]) x = ch[x][1]; 89 splay(x), ch[x][1] = y, p[y] = x, update(x); 90 } 91 92 int main() { 93 #ifdef DEBUG 94 freopen("in.txt", "r", stdin); 95 #endif 96 97 int n; scanf("%d", &n); 98 for(int i = 1; i <= n; i++) { 99 int fa; scanf("%d", &fa); 100 fa = min(fa + i, n + 1); 101 G[fa].push_back(i); 102 } 103 104 dfs(n + 1); 105 106 { 107 int x = (n + 1) * 2 + 1; 108 ch[x][1] = x + 1, p[ch[x][1]] = x; 109 ch[x+1][0] = build((n + 1) << 1); 110 p[ch[x+1][0]] = x+1; 111 update(x+1), update(x); 112 } 113 114 int m; scanf("%d", &m); 115 while(m--) { 116 int opt, u, fa; 117 scanf("%d%d", &opt, &u); ++u; 118 if(opt == 1) { 119 int x = get_suf(dfn[0][u]); 120 splay(x); 121 printf("%d\n", sum[ch[x][0]] - 1); 122 } else { 123 scanf("%d", &fa); 124 fa = min(fa + u, n + 1); 125 int l = get_pre(dfn[0][u]); 126 split(l); 127 int r = split(dfn[1][u]); 128 merge(l, r); 129 split(dfn[0][fa]); 130 merge(dfn[0][fa], dfn[1][u]); 131 merge(dfn[1][u], dfn[1][fa]); 132 } 133 } 134 135 return 0; 136 }
原文出处http://www.cnblogs.com/showson/