[关闭]
@2368860385 2018-02-03T07:17:10.000000Z 字数 21555 阅读 157

省选数据结构模板

这边不包括属于NOIP难度级别的基础数据结果,包括并查集,树状数组,

快速读入

  1. inline ll read(){
  2. ll f=1,x=0;char ch;
  3. do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
  4. do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
  5. return f*x;
  6. }

线段树 洛谷 P3372

如题,已知一个数列,你需要进行下面两种操作:

  1. 将某区间每一个数加上x
  2. 求出某区间每一个数的和
  1. #include <bits/stdc++.h>
  2. const int N = 100005;
  3. typedef long long ll;
  4. using namespace std;
  5. int a[N], n, m;
  6. //快读read()略
  7. ll sumv[N << 2], addv[N << 2];
  8. #define lson (o << 1)
  9. #define rson (o << 1 | 1)
  10. inline void pushup( int o ) {
  11. sumv[o] = sumv[lson] + sumv[rson];
  12. }
  13. inline void pushdown( int o, int l, int r ) {
  14. if ( !addv[o] )
  15. return;
  16. ll tag = addv[o]; addv[o] = 0; int mid = (l + r) >> 1;
  17. addv[lson] += tag; addv[rson] += tag;
  18. sumv[lson] += tag * 1LL * (mid - l + 1); sumv[rson] += tag * 1LL * (r - mid);
  19. }
  20. inline void build( int o, int l, int r ) {
  21. if ( l == r ) {
  22. sumv[o] = a[l]; return;
  23. }
  24. int mid = (l + r) >> 1;
  25. build( lson, l, mid ); build( rson, mid + 1, r );
  26. pushup( o );
  27. }
  28. inline void optadd( int o, int l, int r, int ql, int qr, ll v ) {
  29. if ( ql <= l && r <= qr ) {
  30. sumv[o] += v * 1LL * (r - l + 1); addv[o] += v; return;
  31. }
  32. int mid = (l + r) >> 1; pushdown( o, l, r );
  33. if ( ql <= mid )
  34. optadd( lson, l, mid, ql, qr, v );
  35. if ( qr > mid )
  36. optadd( rson, mid + 1, r, ql, qr, v );
  37. pushup( o );
  38. }
  39. inline ll querysum( int o, int l, int r, int ql, int qr ) {
  40. if ( ql <= l && r <= qr )
  41. return(sumv[o]);
  42. pushdown( o, l, r );
  43. int mid = (l + r) >> 1; ll ans = 0;
  44. if ( ql <= mid )
  45. ans += querysum( lson, l, mid, ql, qr );
  46. if ( qr > mid )
  47. ans += querysum( rson, mid + 1, r, ql, qr );
  48. return(ans);
  49. }
  50. int main() {
  51. n = read(); m = read();
  52. for ( int i = 1; i <= n; i++ )
  53. a[i] = read();
  54. build( 1, 1, n );
  55. while ( m-- ) {
  56. int opt = read(), l = read(), r = read();
  57. if ( opt == 1 ) {
  58. ll k = read(); optadd( 1, 1, n, l, r, k );
  59. }else printf( "%lld\n", querysum( 1, 1, n, l, r ) );
  60. }
  61. }

平衡树(splay 伸展树) 洛谷 P3369

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:

  1. 插入x数
  2. 删除x数(若有多个相同的数,因只删除一个)
  3. 查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)
  4. 查询排名为x的数
  5. 求x的前驱(前驱定义为小于x,且最大的数)
  6. 求x的后继(后继定义为大于x,且最小的数)
  1. #include <cstdio>
  2. #include <iostream>
  3. #include <cstring>
  4. #include <algorithm>
  5. #include <cstdlib>
  6. #define maxn 100010
  7. using namespace std;
  8. struct Splay {
  9. struct Node {
  10. int v, s;
  11. Node *ch[2];
  12. void maintain() {
  13. s = ch[0]->s + ch[1]->s + 1;
  14. }
  15. int cmp( int k ) {
  16. int d = k - ch[0]->s;
  17. if ( d == 1 )
  18. return(-1);
  19. return(d <= 0 ? 0 : 1);
  20. }
  21. };
  22. Node Pr[maxn], *root, *null; int cnt;
  23. void init() {
  24. cnt = 0;
  25. null = &Pr[0]; null->s = 0; null->v = 123456; root = null;
  26. }
  27. Node* New( int x ) {
  28. Pr[++cnt].v = x; Pr[cnt].ch[0] = Pr[cnt].ch[1] = null; Pr[cnt].s = 1;
  29. return(&Pr[cnt]);
  30. }
  31. void rotate( Node* &i, int d ) {
  32. Node* k = i->ch[d ^ 1];
  33. i->ch[d ^ 1] = k->ch[d]; k->ch[d] = i;
  34. i->maintain(); k->maintain(); i = k;
  35. }
  36. void splay( Node* &i, int k ) {
  37. int d = i->cmp( k );
  38. if ( d == 1 )
  39. k -= i->ch[0]->s + 1;
  40. if ( d != -1 ) {
  41. Node *p = i->ch[d]; int d2 = p->cmp( k );
  42. int k2 = d2 == 0 ? k : k - p->ch[0]->s - 1;
  43. if ( d2 != -1 )
  44. {
  45. splay( p->ch[d2], k2 );
  46. if ( d == d2 )
  47. rotate( i, d ^ 1 );
  48. else rotate( i->ch[d], d );
  49. }
  50. rotate( i, d ^ 1 );
  51. }
  52. }
  53. void Insert( Node* &i, int x, int & d ) {
  54. if ( i == null ) {
  55. i = New( x ); return;
  56. }
  57. if ( x <= i->v )
  58. Insert( i->ch[0], x, d );
  59. else d += i->ch[0]->s + 1, Insert( i->ch[1], x, d );
  60. if ( i != null )
  61. i->maintain();
  62. }
  63. void insert( int x ) {
  64. int d = 1;
  65. Insert( root, x, d );
  66. splay( root, d );
  67. }
  68. int find( int x ) {
  69. int ans = 0; Node *p = root; bool flag = false;
  70. while ( p != null ) {
  71. if ( p->v == x )
  72. flag = true;
  73. if ( x <= p->v )
  74. p = p->ch[0];
  75. else ans += p->ch[0]->s + 1, p = p->ch[1];
  76. }
  77. if ( !flag )
  78. return(0);
  79. return(ans + 1);
  80. }
  81. int kth( Node* i, int k ) {
  82. if ( k == i->ch[0]->s + 1 )
  83. return(i->v);
  84. if ( k <= i->ch[0]->s )
  85. return(kth( i->ch[0], k ) );
  86. else return(kth( i->ch[1], k - i->ch[0]->s - 1 ) );
  87. }
  88. int pre( int x ) {
  89. Node* p = root; int ans;
  90. while ( p != null ) {
  91. if ( p->v < x )
  92. ans = p->v;
  93. if ( x <= p->v )
  94. p = p->ch[0];
  95. else p = p->ch[1];
  96. }
  97. return(ans);
  98. }
  99. int nex( int x ) {
  100. Node* p = root; int ans;
  101. while ( p != null ) {
  102. if ( p->v > x )
  103. ans = p->v;
  104. if ( x >= p->v )
  105. p = p->ch[1];
  106. else p = p->ch[0];
  107. }
  108. return(ans);
  109. }
  110. Node* merge( Node* left, Node* right ) {
  111. if ( left == null )
  112. return(right);
  113. if ( right == null )
  114. return(left);
  115. splay( left, left->s );
  116. left->ch[1] = right;
  117. left->maintain();
  118. return(left);
  119. }
  120. void Delete( int x ) {
  121. int d = find( x );
  122. if ( !d )
  123. return;
  124. splay( root, d );
  125. root = merge( root->ch[0], root->ch[1] );
  126. }
  127. } splay;
  128. int main() {
  129. int n;
  130. scanf( "%d", &n );
  131. splay.init();
  132. while ( n-- ) {
  133. int opt, x;
  134. scanf( "%d%d", &opt, &x );
  135. if ( opt == 1 ) splay.insert( x );
  136. if ( opt == 2 ) splay.Delete( x );
  137. if ( opt == 3 ) printf( "%d\n", splay.find( x ) );
  138. if ( opt == 4 ) int k = splay.kth( splay.root, x ); printf( "%d\n", k );
  139. if ( opt == 5 ) printf( "%d\n", splay.pre( x ) );
  140. if ( opt == 6 ) printf( "%d\n", splay.nex( x ) );
  141. }
  142. return(0);
  143. }

平衡树(旋转Treap) 洛谷 P3369

题面同上

  1. #include <iostream>
  2. #include <cstring>
  3. #include <cstdio>
  4. #include <algorithm>
  5. #define N 100005
  6. #define inf 1000000007
  7. using namespace std;
  8. int n;
  9. //快读read()略
  10. struct Treap {
  11. int l[N], r[N], val[N], rnd[N], size[N], w[N], sz, ans, rt;
  12. inline void pushup( int x ) {
  13. size[x] = size[l[x]] + size[r[x]] + w[x];
  14. }
  15. void rturn( int &k ) {
  16. int t = l[k]; l[k] = r[t]; r[t] = k; size[t] = size[k]; pushup( k ); k = t;
  17. }
  18. void lturn( int &k ) {
  19. int t = r[k]; r[k] = l[t]; l[t] = k; size[t] = size[k]; pushup( k ); k = t;
  20. }
  21. void ins( int &k, int x ) {
  22. if ( k == 0 ) {
  23. sz++; k = sz; size[k] = 1; w[k] = 1; val[k] = x; rnd[k] = rand(); return;
  24. }
  25. size[k]++;
  26. if ( val[k] == x )
  27. w[k]++;
  28. else if ( val[k] < x ) {
  29. ins( r[k], x );
  30. if ( rnd[r[k]] < rnd[k] )
  31. lturn( k );
  32. }else{
  33. ins( l[k], x );
  34. if ( rnd[l[k]] < rnd[k] )
  35. rturn( k );
  36. }
  37. }
  38. void del( int &k, int x ) {
  39. if ( !k )
  40. return;
  41. if ( val[k] == x ) {
  42. if ( w[k] > 1 ) {
  43. w[k]--; size[k]--; return;
  44. }
  45. if ( l[k] * r[k] == 0 )
  46. k = l[k] + r[k];
  47. else if ( rnd[l[k]] < rnd[r[k]] )
  48. rturn( k ), del( k, x );
  49. else lturn( k ), del( k, x );
  50. }else if ( val[k] < x ) {
  51. size[k]--; del( r[k], x );
  52. }else {
  53. size[k]--; del( l[k], x );
  54. }
  55. }
  56. int queryrank( int k, int x ) {
  57. if ( !k )
  58. return(0);
  59. if ( val[k] == x )
  60. return(size[l[k]] + 1);
  61. else if ( x > val[k] )
  62. return(size[l[k]] + w[k] + queryrank( r[k], x ) );
  63. else return(queryrank( l[k], x ) );
  64. }
  65. int querynum( int k, int x ) {
  66. if ( k == 0 )
  67. return(0);
  68. if ( x <= size[l[k]] )
  69. return(querynum( l[k], x ) );
  70. else if ( x > size[l[k]] + w[k] )
  71. return(querynum( r[k], x - size[l[k]] - w[k] ) );
  72. else return(val[k]);
  73. }
  74. void querypre( int k, int x ) {
  75. if ( k == 0 )
  76. return;
  77. if ( val[k] < x ) {
  78. ans = k; querypre( r[k], x );
  79. }else querypre( l[k], x );
  80. }
  81. void querysub( int k, int x ) {
  82. if ( k == 0 )
  83. return;
  84. if ( val[k] > x ) {
  85. ans = k; querysub( l[k], x );
  86. }else querysub( r[k], x );
  87. }
  88. } T;
  89. int main() {
  90. n = read(); int opt, x;
  91. for ( int i = 1; i <= n; i++ ) {
  92. opt = read(), x = read();
  93. switch ( opt ) {
  94. case 1: T.ins( T.rt, x ); break;
  95. case 2: T.del( T.rt, x ); break;
  96. case 3: printf( "%d\n", T.queryrank( T.rt, x ) ); break;
  97. case 4: printf( "%d\n", T.querynum( T.rt, x ) ); break;
  98. case 5: T.ans = 0; T.querypre( T.rt, x ); printf( "%d\n", T.val[T.ans] ); break;
  99. case 6: T.ans = 0; T.querysub( T.rt, x ); printf( "%d\n", T.val[T.ans] ); break;
  100. }
  101. }
  102. return(0);
  103. }

平衡树(非旋Treap) 洛谷 P3369

题面同上

  1. #include < bits/stdc ++.h>
  2. #define N 100010
  3. #define mp make_pair
  4. using namespace std;
  5. typedef pair < int, int> par;
  6. int n, x, rt;
  7. struct Treap_Without_rotate{
  8. int ls[N], rs[N], rnd[N], val[N], size[N], cnt;
  9. inline void pushup(int x){size[x] = size[ls[x]] + size[rs[x]] + 1; }
  10. par split(int k, int x){
  11. if(!x)return mp(0, k);
  12. int l = ls[k], r = rs[k];
  13. if(x == size[l]){
  14. ls[k] = 0; pushup(k);
  15. return mp(l, k);
  16. }
  17. if(x == size[l] + 1){
  18. rs[k] = 0; pushup(k);
  19. return mp(k, r);
  20. }
  21. if(x < size[l]){
  22. par tmp = split(l, x);
  23. ls[k] = tmp.second; pushup(k);
  24. return mp(tmp.first, k);
  25. }
  26. par tmp = split(r, x - size[l] - 1);
  27. rs[k] = tmp.first; pushup(k);
  28. return mp(k, tmp.second);
  29. }
  30. int merge(int x, int y){
  31. if(x == 0 || y == 0)
  32. return x + y;
  33. if(rnd[x] < rnd[y]){
  34. rs[x] = merge(rs[x], y); pushup(x);
  35. return x;
  36. }
  37. else{
  38. ls[y] = merge(x, ls[y]); pushup(y);
  39. return y;
  40. }
  41. }
  42. int queryrank(int x, int k){
  43. int ans = 0, tmp = (int)1e9;
  44. while(k){
  45. if(x == val[k])tmp = min(tmp, ans + size[ls[k]] + 1);
  46. if(x>val[k])ans + = size[ls[k]] + 1, k = rs[k];
  47. else k = ls[k];
  48. }
  49. return tmp == (int)1e9?ans:tmp;
  50. }
  51. int find(int x, int k){
  52. for(; ; ){
  53. if(size[ls[k]] == x - 1)return val[k];
  54. if(size[ls[k]]>x - 1)k = ls[k];
  55. else x = x - size[ls[k]] - 1, k = rs[k];
  56. }
  57. }
  58. int querypre(int x, int k){
  59. int ans = -(int)1e9;
  60. while(k){
  61. if(val[k] < x)ans = max(ans, val[k]), k = rs[k];
  62. else k = ls[k];
  63. }
  64. return ans;
  65. }
  66. int querysub(int x, int k){
  67. int ans = (int)1e9;
  68. while(k){
  69. if(val[k]>x)ans = min(ans, val[k]), k = ls[k];
  70. else k = rs[k];
  71. }
  72. return ans;
  73. }
  74. void ins(int x){
  75. int k = queryrank(x, rt); par tmp = split(rt, k);
  76. val[ ++cnt] = x; rnd[cnt] = rand(); size[cnt] = 1;
  77. rt = merge(tmp.first, cnt); rt = merge(rt, tmp.second);
  78. }
  79. void del(int x){
  80. int k = queryrank(x, rt); par t1 = split(rt, k), t2 = split(t1.first, k - 1);
  81. rt = merge(t2.first, t1.second);
  82. }
  83. } T;
  84. int main(){
  85. n = read(); srand(2333333);
  86. for(int i = 1; i < = n; i ++){
  87. int opt = read(), x = read();
  88. if(opt == 1)T.ins(x);
  89. if(opt == 2)T.del(x);
  90. if(opt == 3)printf("%d\n", T.queryrank(x, rt));
  91. if(opt == 4)printf("%d\n", T.find(x, rt));
  92. if(opt == 5)printf("%d\n", T.querypre(x, rt));
  93. if(opt == 6)printf("%d\n", T.querysub(x, rt));
  94. }
  95. return 0;
  96. }

树链剖分 洛谷P3384

如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:

  1. 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z
  2. 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和
  3. 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z
  4. 格式: 4 x 表示求以x为根节点的子树内所有节点值之和
  1. #include<cstdio>
  2. #include<cmath>
  3. #include<algorithm>
  4. #include<cstring>
  5. using namespace std;
  6. const int maxn = 300000;
  7. struct tree{int l, r, v, lazy; }node[2*maxn];
  8. int first[maxn], last[maxn], nxt[maxn], a[maxn], w[maxn], tid[maxn],
  9. e[maxn], top[maxn], rank[maxn], size[maxn], r[maxn], tt[maxn], father[maxn],
  10. n, m, k, mod, x, y, g, i, s, tot, z;
  11. void add(int x, int y){
  12. a[++k] = y; tt[x]++;
  13. if(first[x] == 0)
  14. first[x] = k;
  15. else
  16. nxt[last[x]] = k;
  17. last[x] = k;
  18. }
  19. void build(int u, int l, int r){
  20. int mid = (l + r) / 2; node[u].l = l; node[u].r = r;
  21. if(l == r)return;
  22. build(u*2, l, mid);
  23. build(u*2+1, mid+1, r);
  24. }
  25. void down(int u){
  26. if(node[u].lazy == 0)return;
  27. node[u].v += node[u].lazy*(node[u].r-node[u].l+1)%mod;
  28. node[u*2].lazy += node[u].lazy; node[u*2+1].lazy += node[u].lazy;
  29. node[u].lazy = 0;
  30. }
  31. void change(int u, int l, int r, int cont){
  32. if(node[u].l > r||node[u].r<l)return;
  33. if(node[u].l >= l&&node[u].r< = r){
  34. node[u].lazy += cont; down(u);
  35. return;
  36. }
  37. change(u*2, l, r, cont);
  38. change(u*2+1, l, r, cont);
  39. down(u*2); down(u*2+1);
  40. node[u].v = (node[u*2].v+node[u*2+1].v)%mod;
  41. }
  42. int query(int u, int l, int r){
  43. if(node[u].l > r||node[u].r<l)return 0;
  44. if(node[u].l >= l&&node[u].r< = r)return (node[u].v)%mod;
  45. down(u*2); down(u*2+1);
  46. return(query(u*2, l, r)+query(u*2+1, l, r))%mod;
  47. }
  48. void dfs(int u, int fa){
  49. int i = 0; size[u] = 1; r[u] = r[fa]+1;
  50. father[u] = fa;
  51. for(i = first[u]; i; i = nxt[i])
  52. if(a[i]! = fa)
  53. {
  54. dfs(a[i], u);
  55. size[u] += size[a[i]];
  56. }
  57. }
  58. void dfs2(int u, int head){
  59. int i, mson = 0;
  60. top[u] = head; tid[u] = ++tot; rank[tid[u]] = tot;
  61. change(1, tot, tot, w[u]);
  62. if(tt[u] == 1&&u! = s){
  63. e[u] = u;
  64. return;
  65. }
  66. for(i = first[u]; i>0; i = nxt[i])
  67. if(size[a[i]]<size[u]&&size[a[i]]>size[mson])
  68. mson = a[i];
  69. dfs2(mson, head);
  70. e[u] = e[mson];
  71. for(i = first[u]; i>0; i = nxt[i])
  72. if(size[a[i]]<size[u]&&a[i]! = mson){
  73. dfs2(a[i], a[i]); e[u] = e[a[i]];
  74. }
  75. }
  76. void schange(int x, int y, int cont){
  77. while(top[x]! = top[y]) {
  78. if(r[top[x]]<r[top[y]])swap(x, y);
  79. change(1, tid[top[x]], tid[x], cont);
  80. x = father[top[x]];
  81. }
  82. if(tid[x]>tid[y])swap(x, y);
  83. change(1, tid[x], tid[y], cont);
  84. }
  85. int squery(int x, int y){
  86. int ans = 0;
  87. while(top[x]! = top[y]){
  88. if(r[top[x]]<r[top[y]])swap(x, y);
  89. ans += query(1, tid[top[x]], tid[x]);
  90. ans %= mod;
  91. x = father[top[x]];
  92. }
  93. if(tid[x]>tid[y])swap(x, y);
  94. ans += query(1, tid[x], tid[y]);
  95. ans %= mod;
  96. return ans;
  97. }
  98. int main(){
  99. scanf("%d%d%d%d", &n, &m, &s, &mod);
  100. for(i = 1; i< = n; i++)scanf("%d", &w[i]);
  101. for(i = 1; i< = n-1; i++){scanf("%d%d", &x, &y); add(x, y); add(y, x); }
  102. build(1, 1, n);
  103. dfs(s, 0);
  104. dfs2(s, s);
  105. for(i = 1; i< = m; i++){
  106. scanf("%d", &g);
  107. if(g == 1){
  108. scanf("%d%d%d", &x, &y, &z);
  109. schange(x, y, z);
  110. }
  111. if(g == 2){
  112. scanf("%d%d", &x, &y);
  113. printf("%d\n", squery(x, y)%mod);
  114. }
  115. if(g == 3){
  116. scanf("%d%d", &x, &y);
  117. change(1, tid[x], tid[e[x]], y);
  118. }
  119. if(g == 4){
  120. scanf("%d", &x);
  121. printf("%d\n", query(1, tid[x], tid[e[x]])%mod);
  122. }
  123. }
  124. return 0;
  125. }

给定n个点以及每个点的权值,要你处理接下来的m个操作。操作有4种。操作从0到3编号。点从1到n编号。

0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和。保证x到y是联通的。

1:后接两个整数(x,y),代表连接x到y,若x到y已经联通则无需连接。

2:后接两个整数(x,y),代表删除边(x,y),不保证边(x,y)存在。

3:后接两个整数(x,y),代表将点x上的权值变成y。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<cstdlib>
  5. #include<algorithm>
  6. #include<cmath>
  7. #define N 300005
  8. using namespace std;
  9. int n,m,top;
  10. int c[N][2],fa[N],v[N],s[N],q[N];
  11. bool rev[N];
  12. //略去快速读入read()
  13. void update(int x){
  14. int l=c[x][0],r=c[x][1];
  15. s[x]=s[l]^s[r]^v[x];
  16. }
  17. void pushdown(int x){
  18. int l=c[x][0],r=c[x][1];
  19. if(rev[x]){
  20. rev[x]^=1;rev[l]^=1;rev[r]^=1;
  21. swap(c[x][0],c[x][1]);
  22. }
  23. }
  24. bool isroot(int x){
  25. return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;
  26. }
  27. void rotate(int x){
  28. int y=fa[x],z=fa[y],l,r;
  29. if(c[y][0]==x)l=0;else l=1;r=l^1;
  30. if(!isroot(y)) {
  31. if(c[z][0]==y)c[z][0]=x;else c[z][1]=x;
  32. }
  33. fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
  34. c[y][l]=c[x][r];c[x][r]=y;
  35. update(y);update(x);
  36. }
  37. void splay(int x){
  38. top=0;q[++top]=x;
  39. for(int i=x;!isroot(i);i=fa[i])
  40. q[++top]=fa[i];
  41. for(int i=top;i;i--)
  42. pushdown(q[i]);
  43. while(!isroot(x)){
  44. int y=fa[x],z=fa[y];
  45. if(!isroot(y))
  46. {
  47. if(c[y][0]==x^c[z][0]==y)rotate(x);
  48. else rotate(y);
  49. }
  50. rotate(x);
  51. }
  52. }
  53. void access(int x){
  54. for(int t=0;x;t=x,x=fa[x])
  55. splay(x),c[x][1]=t,update(x);
  56. }
  57. void makeroot(int x){
  58. access(x);splay(x);rev[x]^=1;
  59. }
  60. int find(int x){
  61. access(x);splay(x);
  62. while(c[x][0])x=c[x][0];
  63. return x;
  64. }
  65. void cut(int x,int y){
  66. makeroot(x);access(y);splay(y);
  67. if(c[y][0]==x)c[y][0]=fa[x]=0;
  68. }
  69. void link(int x,int y){
  70. makeroot(x);fa[x]=y;
  71. }
  72. int main(){
  73. n=read();m=read();
  74. for(int i=1;i<=n;i++)v[i]=read(),s[i]=v[i];
  75. int opt,x,y;
  76. for(int i=1;i<=m;i++){
  77. opt=read();x=read();y=read();
  78. switch(opt){
  79. case 0:makeroot(x);access(y);splay(y);printf("%d\n",s[y]);break;
  80. case 1:if(find(x)!=find(y))link(x,y);break;
  81. case 2:if(find(x)==find(y))cut(x,y);break;
  82. case 3:access(x);splay(x);v[x]=y;update(x);break;
  83. }
  84. }
  85. return 0;
  86. }

可持久化Trie 洛谷P2633

给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。

nzhtl1477认为这个数据结构应该叫fingertree

  1. #include <iostream>
  2. #include <stdio.h>
  3. #include <vector>
  4. #define ratio 4
  5. #define new_Node(s, v, a, b) (& (* st[ cnt++ ] = Node(s, v, a, b)))
  6. #define merge(a, b) new_Node(a->size + b->size, b->value, a, b)
  7. #define MAXN 100010
  8. using namespace std;
  9. struct Node {
  10. int size, value;
  11. Node * left, * right;
  12. Node(int s, int v, Node * a, Node * b) : size(s), value(v), left(a), right(b) {}
  13. Node() {}
  14. } * null, * root[ MAXN ], * st[4000000], t[4000000];
  15. int n, m, cnt, x, y, k, a[ MAXN ], fa[ MAXN ][20], dep[ MAXN ], ans;
  16. vector < int > linker[ MAXN ];
  17. void insert(int x, Node * cur) {
  18. if(cur->size == 1) {
  19. cur->left = new_Node(1, min(cur->value, x), null, null);
  20. cur->right = new_Node(1, max(cur->value, x), null, null);
  21. }
  22. else insert(x, x > cur->left->value ? cur->right : cur->left);
  23. cur->size++, cur->value = cur->right->value;
  24. }
  25. int rank(int x, Node * cur) {
  26. if(cur->size == 1) return 1;
  27. return x > cur->left->value ? rank(x, cur->right) + cur->left->size : rank(x, cur->left);
  28. }
  29. int find(int x, Node * cur) {
  30. if(cur->size == 1) return cur->value;
  31. return x > cur->left->size ? find(x - cur->left->size, cur->right) : find(x, cur->left);
  32. }
  33. Node * modify(int x, Node * a) {
  34. Node * cur = new_Node(a->size, a->value + 1, a->left, a->right);
  35. if(cur->left)
  36. if(x > cur->left->size) cur->right = modify(x - cur->left->size, cur->right);
  37. else cur->left = modify(x, cur->left);
  38. return cur;
  39. }
  40. int find(int x, Node * a, Node * b, Node * c, Node * d) {
  41. int mid = a->left->value + b->left->value - c->left->value - d->left->value;
  42. if(a->size == 1) return 1;
  43. if(x > mid) return find(x - mid, a->right, b->right, c->right, d->right) + a->left->size;
  44. return find(x, a->left, b->left, c->left, d->left);
  45. }
  46. Node * build(int l, int r) {
  47. if(l == r) return new_Node(1, 0, null, null);
  48. Node * left = build(l, (l + r) >> 1), * right = build(((l + r) >> 1) + 1, r);
  49. return new_Node(r - l + 1, 0, left, right);
  50. }
  51. #define cur linker[x][i]
  52. void dfs(int x) {
  53. root[x] = modify(rank(a[x], root[ n + 1 ]), root[ fa[x][0] ]);
  54. dep[x] = dep[ fa[x][0] ] + 1;
  55. for(int i = 0 ; i < linker[x].size() ; i++)
  56. if(cur != fa[x][0])
  57. fa[ cur ][0] = x, dfs(cur);
  58. }
  59. inline int lca(int x, int y) {
  60. if(dep[x] < dep[y]) swap(x, y);
  61. for(register int i = 0 ; i < 20 ; i++)
  62. if((dep[x] - dep[y]) & (1 << i))
  63. x = fa[x][i];
  64. if(x == y) return x;
  65. for(register int i = 19 ; i >= 0 ; i--)
  66. if(fa[x][i] != fa[y][i])
  67. x = fa[x][i], y = fa[y][i];
  68. return fa[x][0];
  69. }
  70. //略去读入优化read()
  71. inline void addedge(int x, int y) {
  72. linker[x].push_back(y), linker[y].push_back(x);
  73. }
  74. int main() {
  75. n = read(), m = read();
  76. for(register int i = 0 ; i < 4000000 ; i++) st[i] = & t[i];
  77. null = new_Node(0, 0, 0, 0);
  78. root[ n + 1 ] = new_Node(1, 2147483647, null, null);
  79. root[0] = build(1, n);
  80. for(register int i = 1 ; i <= n ; i++) insert(a[i] = read(), root[ n + 1 ]);
  81. for(register int i = 1 ; i < n ; i++) addedge(read(), read());
  82. dfs(1);
  83. for(register int j = 1 ; j < 20 ; j++)
  84. for(register int i = 1 ; i <= n ; i++)
  85. fa[i][j] = fa[ fa[i][j - 1] ][j - 1];
  86. while(m--)
  87. {
  88. x = read() ^ ans, y = read(), k = read();
  89. int l = lca(x, y);
  90. printf("%d", ans = find(find(k, root[x], root[y], root[l], root[ fa[l][0] ]), root[ n + 1 ]));
  91. if(m) putchar('\n');
  92. }
  93. return 0;
  94. }

左偏树 可并堆 洛谷P3377

如题,一开始有N个小根堆,每个堆包含且仅包含一个数。接下来需要支持两种操作:

操作1: 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或第y个数已经被删除或第x和第y个数在用一个堆内,则无视此操作)

操作2: 2 x 输出第x个数所在的堆最小数,并将其删除(若第x个数已经被删除,则输出-1并无视删除操作)

  1. #include<cstdio>
  2. #include<algorithm>
  3. using namespace std;
  4. const int N=101000;
  5. struct Leftist{
  6. int lch,rch,key,fa,dist;
  7. }h[N];
  8. int n,m;
  9. // 省略读入优化read()
  10. int merge(int u,int v){
  11. if (!u || !v)return u+v;
  12. if (h[u].key>h[v].key || (h[u].key==h[v].key && u>v))swap(u,v);
  13. int &ul=h[u].lch,&ur=h[u].rch;
  14. ur=merge(ur,v);
  15. h[ur].fa=u;
  16. if (h[ul].dist<h[ur].dist)swap(ul,ur);
  17. h[u].dist=h[ur].dist+1;
  18. return u;
  19. }
  20. void erase(int u){
  21. int ul=h[u].lch,ur=h[u].rch;
  22. h[u].key=-1;h[ul].fa=0;h[ur].fa=0;
  23. merge(ul,ur);
  24. }
  25. int find(int x){
  26. return h[x].fa?find(h[x].fa):x;
  27. }
  28. int main(){
  29. n=read(),m=read();
  30. h[0].dist=-1;
  31. for (int i=1;i<=n;i++)
  32. h[i].key=read();
  33. for (int i=1;i<=m;i++){
  34. int opt,x,y;
  35. opt=read(),x=read();
  36. if (opt==1){
  37. y=read();
  38. if (h[x].key!=-1 && h[y].key!=-1){
  39. int p=find(x),q=find(y);
  40. if (p!=q)merge(p,q);
  41. }
  42. }else if (opt==2){
  43. if (h[x].key==-1)printf("-1\n");
  44. else{
  45. int p=find(x);
  46. printf("%d\n",h[p].key);
  47. erase(p);
  48. }
  49. }
  50. }
  51. return 0;
  52. }

树套树 线段树套treap 洛谷P3380

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:

  1. 查询k在区间内的排名
  2. 查询区间内排名为k的值
  3. 修改某一位值上的数值
  4. 查询k在区间内的前驱(前驱定义为严格小于x,且最大的数,若不存在输出-2147483647)
    5.查询k在区间内的后继(后继定义为严格大于x,且最小的数,若不存在输出2147483647)

这题有多种复杂度不同写法,下面给出的是一个线段树套Treap平衡树的做法。其中的Treap是另外一种写法。

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <cstdio>
  4. #include <cstdlib>
  5. #pragma GCC optimize("O3")
  6. #define N 50020
  7. #define M 100000000
  8. #define INFINITE 2147483647
  9. using namespace std;
  10. class Node {
  11. public:
  12. Node *s[2];
  13. int v, e, w, z;
  14. Node(int _v, int _e, int _w, int _z) : v(_v), e(_e), w(_w), z(_z){
  15. s[0] = s[1] = NULL;
  16. return;
  17. }
  18. int Size(int k) {
  19. return s[k] ? s[k] -> z : 0;
  20. }
  21. void Update(void) {
  22. z = Size(0) + Size(1) + w;
  23. return;
  24. }
  25. };
  26. class Treap {
  27. public:
  28. Node *r;
  29. void RotateTreap(Node *&x, int k) {
  30. Node *t;
  31. t = x -> s[!k];
  32. x -> s[!k] = t -> s[k];
  33. t -> s[k] = x;
  34. x -> Update();
  35. t -> Update();
  36. x = t;
  37. return;
  38. }
  39. void InsertTreap(Node *&x, int v, int w = 1) {
  40. if(!x)
  41. x = new Node(v, rand(), w, w);
  42. else if(x -> v == v)
  43. x -> w += w;
  44. else if(x -> v < v) {
  45. InsertTreap(x -> s[1], v, w);
  46. if(x -> s[1] -> e < x -> e)
  47. RotateTreap(x, 0);
  48. }
  49. else {
  50. InsertTreap(x -> s[0], v, w);
  51. if(x -> s[0] -> e < x -> e)
  52. RotateTreap(x, 1);
  53. }
  54. x -> Update();
  55. return;
  56. }
  57. void RemoveTreap(Node *&x, int v) {
  58. Node *t;
  59. int k;
  60. if(x -> v == v) {
  61. if(x -> w > 1)
  62. x -> w --;
  63. else {
  64. if(!x -> s[0]) {
  65. t = x;
  66. x = x -> s[1];
  67. delete t;
  68. return;
  69. }
  70. if(!x -> s[1]) {
  71. t = x;
  72. x = x -> s[0];
  73. delete t;
  74. return;
  75. }
  76. k = x -> s[0] -> e < x -> s[1] -> e;
  77. RotateTreap(x, k);
  78. RemoveTreap(x -> s[k], v);
  79. }
  80. }
  81. else {
  82. k = x -> v < v;
  83. RemoveTreap(x -> s[k], v);
  84. if(x -> s[k] && x -> s[k] -> e < x -> e)
  85. RotateTreap(x, x -> s[k] -> e < x -> e);
  86. }
  87. x -> Update();
  88. return;
  89. }
  90. int RankTreap(Node *x, int v) {
  91. int o;
  92. for(o = 0;x;)
  93. if(x -> v == v) {
  94. //printf("G %d\n", x -> Size(0));
  95. return o + x -> Size(0);
  96. }
  97. else if(x -> v < v) {
  98. o += x -> Size(0) + x -> w;
  99. x = x -> s[1];
  100. }
  101. else
  102. x = x -> s[0];
  103. return o;
  104. }
  105. int CountTreap(Node *x, int v) {
  106. while(x) {
  107. if(x -> v == v)
  108. return x -> w;
  109. x = x -> s[x -> v < v];
  110. }
  111. return 0;
  112. }
  113. int PrevTreap(Node *x, int v) {
  114. int o;
  115. for(o = -INFINITE;x;)
  116. if(x -> v >= v)
  117. x = x -> s[0];
  118. else {
  119. o = max(o, x -> v);
  120. x = x -> s[1];
  121. }
  122. return o;
  123. }
  124. int SuffTreap(Node *x, int v) {
  125. int o;
  126. for(o = INFINITE;x;)
  127. if(x -> v <= v)
  128. x = x -> s[1];
  129. else {
  130. o = min(o, x -> v);
  131. x = x -> s[0];
  132. }
  133. return o;
  134. }
  135. void MergeTreap(Node *x) {
  136. if(!x)
  137. return;
  138. MergeTreap(x -> s[0]);
  139. MergeTreap(x -> s[1]);
  140. InsertTreap(r, x -> v, x -> w);
  141. return;
  142. }
  143. };
  144. class Segment {
  145. public:
  146. Treap f[N * 4];
  147. void BuildSegment(int *x, int i, int l, int r) {
  148. if(l >= r) {
  149. f[i].r = NULL;
  150. f[i].InsertTreap(f[i].r, x[l]);
  151. return;
  152. }
  153. BuildSegment(x, i * 2, l, (l + r) / 2);
  154. BuildSegment(x, i * 2 + 1, (l + r) / 2 + 1, r);
  155. f[i].r = NULL;
  156. f[i].MergeTreap(f[i * 2].r);
  157. f[i].MergeTreap(f[i * 2 + 1].r);
  158. /*for(int t = l;t <= r;t ++)
  159. f[i].InsertTreap(f[i].r, x[t]);*/
  160. /*if(f[i * 2].r -> z > f[i * 2 + 1].r -> z) {
  161. f[i] = f[i * 2];
  162. f[i].MergeTreap(f[i * 2 + 1].r);
  163. }
  164. else {
  165. f[i] = f[i * 2 + 1];
  166. f[i].MergeTreap(f[i * 2].r);
  167. }*/
  168. return;
  169. }
  170. int RankSegment(int i, int l, int r, int s, int t, int v) {
  171. if(r < s || l > t)
  172. return 0;
  173. if(l >= s && r <= t)
  174. return f[i].RankTreap(f[i].r, v);
  175. return RankSegment(i * 2, l, (l + r) / 2, s, t, v) + RankSegment(i * 2 + 1, (l + r) / 2 + 1, r, s, t, v);
  176. }
  177. int CountSegment(int i, int l, int r, int s, int t, int v) {
  178. if(r < s || l > t)
  179. return 0;
  180. if(l >= s && r <= t) {
  181. return f[i].RankTreap(f[i].r, v) + f[i].CountTreap(f[i].r, v);
  182. }
  183. return CountSegment(i * 2, l, (l + r) / 2, s, t, v) + CountSegment(i * 2 + 1, (l + r) / 2 + 1, r, s, t, v);
  184. }
  185. int PrevSegment(int i, int l, int r, int s, int t, int v) {
  186. if(r < s || l > t)
  187. return -INFINITE;
  188. if(l >= s && r <= t)
  189. return f[i].PrevTreap(f[i].r, v);
  190. return max(PrevSegment(i * 2, l, (l + r) / 2, s, t, v), PrevSegment(i * 2 + 1, (l + r) / 2 + 1, r, s, t, v));
  191. }
  192. int SuffSegment(int i, int l, int r, int s, int t, int v) {
  193. if(r < s || l > t)
  194. return INFINITE;
  195. if(l >= s && r <= t)
  196. return f[i].SuffTreap(f[i].r, v);
  197. return min(SuffSegment(i * 2, l, (l + r) / 2, s, t, v), SuffSegment(i * 2 + 1, (l + r) / 2 + 1, r, s, t, v));
  198. }
  199. void SetSegment(int *x, int i, int l, int r, int p, int v) {
  200. if(l > p || r < p)
  201. return;
  202. if(l == p && r == p) {
  203. f[i].RemoveTreap(f[i].r, x[p]);
  204. f[i].InsertTreap(f[i].r, v );
  205. return;
  206. }
  207. f[i].RemoveTreap(f[i].r, x[p]);
  208. f[i].InsertTreap(f[i].r, v );
  209. SetSegment(x, i * 2, l, (l + r) / 2, p, v);
  210. SetSegment(x, i * 2 + 1, (l + r) / 2 + 1, r, p, v);
  211. return;
  212. }
  213. int KthSegment(int s, int t, int k, int n, pair<int, int> v) {
  214. int l, m, r;
  215. for(l = v.first - 1, r = v.second;l + 1 < r;) {
  216. //printf("%d : %d\n", (l + r) / 2, CountSegment(1, 0, n - 1, s, t, m = (l + r) / 2));
  217. if(CountSegment(1, 0, n - 1, s, t, m = (l + r) / 2) >= k)
  218. r = m;
  219. else
  220. l = m;
  221. }
  222. return r;
  223. }
  224. };
  225. class Segwin {
  226. private:
  227. int n;
  228. int f[N * 4];
  229. int g[N * 4];
  230. public:
  231. void BuildSegwin(int n, int *x) {
  232. int i;
  233. this -> n = n;
  234. for(i = 0;i < n;i ++)
  235. f[i + n] = g[i + n] = x[i];
  236. for(i = n - 1;i > -1;i --) {
  237. f[i] = min(f[i << 1], f[i << 1 | 1]);
  238. g[i] = max(g[i << 1], g[i << 1 | 1]);
  239. }
  240. return;
  241. }
  242. pair<int, int> MixSegwin(int s, int t) {
  243. pair<int, int> o;
  244. for(o = make_pair(INFINITE, -INFINITE), s += n, t += n + 1;s < t;s >>= 1, t >>= 1) {
  245. if(s & 1) {
  246. o.first = min(o.first , f[s]);
  247. o.second = max(o.second, g[s]);
  248. s ++;
  249. }
  250. if(t & 1) {
  251. t --;
  252. o.first = min(o.first , f[t]);
  253. o.second = max(o.second, g[t]);
  254. }
  255. }
  256. return o;
  257. }
  258. void SetSegwin(int p, int v) {
  259. for(p += n, f[p] = g[p] = v;p >>= 1;) {
  260. f[p] = min(f[p << 1], f[p << 1 | 1]);
  261. g[p] = max(g[p << 1], g[p << 1 | 1]);
  262. }
  263. return;
  264. }
  265. };
  266. int a[N];
  267. Segment f;
  268. Segwin g;
  269. int main() {
  270. int n, m, p, l, r, k;
  271. int i;
  272. scanf("%d %d", &n, &m);
  273. for(i = 0;i < n;i ++)
  274. scanf("%d", &a[i]);
  275. f.BuildSegment(a, 1, 0, n - 1);
  276. g.BuildSegwin(n, a);
  277. while(m --) {
  278. scanf("%d %d %d", &p, &l, &r);
  279. if(p != 3) {
  280. l --;
  281. r --;
  282. scanf("%d", &k);
  283. }
  284. if(p == 1)
  285. printf("%d\n", f.RankSegment(1, 0, n - 1, l, r, k) + 1);
  286. if(p == 2)
  287. printf("%d\n", f.KthSegment(l, r, k, n, /*make_pair(0, M)*/g.MixSegwin(l, r)));
  288. //printf("%d\n", f.CountSegment(1, 0, n - 1, l, r, k));
  289. if(p == 3) {
  290. f.SetSegment(a, 1, 0, n - 1, -- l, r);
  291. g.SetSegwin(l, r);
  292. a[l] = r;
  293. }
  294. if(p == 4)
  295. printf("%d\n", f.PrevSegment(1, 0, n - 1, l, r, k));
  296. if(p == 5)
  297. printf("%d\n", f.SuffSegment(1, 0, n - 1, l, r, k));
  298. }
  299. return 0;
  300. }

莫队算法 洛谷P3604

n个人,每个人给了一个小写字母'a'到'z'作为编号

一个区间的人如果满足他们的编号重排之后可以成为一个回文串,则他们可以一起回归天空,即这个区间可以回归天空。

给了m个区间,每次求每个区间中有多少个子区间可以回归天空。

  1. #include <iostream>
  2. #include <stdio.h>
  3. #include <vector>
  4. #include <math.h>
  5. #include <algorithm>
  6. #define MAXN 60010
  7. using namespace std;
  8. int n , m , t , block , belong[ MAXN ];
  9. unsigned short cnt[1 << 26];
  10. char s[ MAXN ];
  11. unsigned int a[ MAXN ] , ans[ MAXN ] , res;
  12. struct ask
  13. {
  14. int l , r , pos;
  15. } q[ MAXN ];
  16. inline bool cmp( const ask & a , const ask & b )
  17. {
  18. return belong[ a.l ] ^ belong[ b.l ] ? belong[ a.l ] < belong[ b.l ] : belong[ a.l ] & 1 ? a.r < b.r : a.r > b.r;
  19. }
  20. inline void insert( int x )
  21. {
  22. for( register int i = 0 ; i < t ; i++ )
  23. res += cnt[ x ^ ( 1 << i ) ];
  24. res += cnt[x]++;
  25. }
  26. inline void erase( int x )
  27. {
  28. for( register int i = 0 ; i < t ; i++ )
  29. res -= cnt[ x ^ ( 1 << i ) ];
  30. res -= --cnt[x];
  31. }
  32. inline int read()
  33. {
  34. register int x = 0 , ch = getchar();
  35. while( !isdigit( ch ) ) ch = getchar();
  36. while( isdigit( ch ) ) x = x * 10 + ch - '0' , ch = getchar();
  37. return x;
  38. }
  39. int main()
  40. {
  41. scanf( "%d %d %s" , &n , &m , s + 1 );
  42. for( register int i = 1 ; i <= n ; i++ ) t = max( t , s[i] - 'a' + 1 );
  43. block = n / sqrt( m * 2 / 3 );
  44. for( register int i = 1 ; i <= n ; i++ ) belong[i] = ( i - 1 ) / block , a[i] = a[i - 1] ^ ( 1ll << s[i] - 'a' );
  45. for( register int i = 1 ; i <= m ; i++ )
  46. q[i].l = read() , q[i].r = read() , q[i].pos = i;
  47. sort( q + 1 , q + m + 1 , cmp );
  48. for( int i = 1 , l = 1 , r = 0 ; i <= m ; i++ )
  49. {
  50. while( l > q[i].l ) insert( a[ --l ] );
  51. while( r < q[i].r ) insert( a[ ++r ] );
  52. while( l < q[i].l ) erase( a[ l++ ] );
  53. while( r > q[i].r ) erase( a[ r-- ] );
  54. insert( a[l - 1] );
  55. ans[ q[i].pos ] = res;
  56. erase( a[l - 1] );
  57. }
  58. for( register int i = 1 ; i <= m ; i++ )
  59. printf( "%u\n" , ans[i] );
  60. return 0;
  61. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注