CodeForeces 842d Vitya and Strange Lesson ——(带lazy标记的01字典树)
Posted Storm_Spirit
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CodeForeces 842d Vitya and Strange Lesson ——(带lazy标记的01字典树)相关的知识,希望对你有一定的参考价值。
给一个序列,每次操作对这个序列中的所有数异或一个x,问每次操作完以后整个序列的mex值。
做法是去重后构建01字典树,异或x就是对root加一个x的lazy标志,每次pushDown时如果lazy的这一位是1,则交换左右儿子。找mex的话只要每次往左走,如果左子树是满的,则往右走,并且加上左边相应造成的贡献。具体见代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 3e5 + 5; 4 typedef long long ll; 5 6 int n, m; 7 struct node 8 { 9 int sz, lazy; 10 node* ch[2]; 11 void init() {sz = 1; lazy = 0; ch[0] = ch[1] = NULL;} 12 }nodes[N<<2], *root; 13 int tot; 14 15 node* getnew() 16 { 17 node *p = &nodes[tot++]; 18 p->init(); 19 return p; 20 } 21 void insert(node *p, int dep, int x) 22 { 23 if(dep == -1) return ; 24 int m = ((x>>dep) & 1); 25 if(p->ch[m] == NULL) 26 { 27 p->ch[m] = getnew(); 28 } 29 insert(p->ch[m], dep-1, x); 30 int szl = p->ch[0] ? p->ch[0]->sz : 0; 31 int szr = p->ch[1] ? p->ch[1]->sz : 0; 32 p->sz = szl + szr + 1; 33 } 34 void down(node *p, int dep) 35 { 36 for(int i=0;i<2;i++) 37 { 38 if(p->ch[i]) p->ch[i]->lazy ^= p->lazy; 39 } 40 if((p->lazy >> dep) & 1) swap(p->ch[0], p->ch[1]); 41 p->lazy = 0; 42 } 43 void solve() 44 { 45 node *p = root; 46 int ans = 0; 47 for(int i=20;i>=0;i--) 48 { 49 down(p, i); 50 if(p->ch[0] && p->ch[0]->sz == (1<<i+1) - 1) 51 { 52 ans |= (1<<i); 53 p = p->ch[1]; 54 } 55 else 56 { 57 p = p->ch[0]; 58 } 59 if(!p) break; 60 } 61 printf("%d\n",ans); 62 } 63 64 map<int, int> mp; 65 int main() 66 { 67 cin >> n >> m; 68 root = getnew(); 69 for(int i=1;i<=n;i++) 70 { 71 int x; scanf("%d",&x); 72 if(mp[x]) continue; 73 insert(root, 20, x); 74 mp[x] = 1; 75 } 76 while(m--) 77 { 78 int x; scanf("%d",&x); 79 root->lazy ^= x; 80 solve(); 81 } 82 return 0; 83 }
还有一个类似的题目,之前青岛场的热身赛,每次需要求的是前k小的和。具体的做法类似,求和时如果左边的sz比k小则直接加上左边的sum并且向右边递归即可。这里需要注意,到当前节点是,如果要求其子树的sum,需要先对其子树进行pushDown,因为其sum已经在其子树要进行交换儿子的时候发生变化了,因此每次pushDown维护sum时需要用log次暴力地算出现在的sum,那么就需要对每个节点维护一个have数组,来记录各位上0和1的位数。具体见代码(含暴力对拍):
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 3e5 + 5; 4 typedef long long ll; 5 6 int n, m; 7 struct node 8 { 9 int sz, lazy; 10 ll sum; 11 node* ch[2]; 12 int have[2][25]; 13 void init() {sz = 0; lazy = 0; sum = 0; ch[0] = ch[1] = NULL; memset(have, 0, sizeof have);} 14 }nodes[N<<2], *root; 15 int tot; 16 17 node* getnew() 18 { 19 node *p = &nodes[tot++]; 20 p->init(); 21 return p; 22 } 23 void insert(node *p, int dep, int x) 24 { 25 if(dep == -1) 26 { 27 for(int i=20;i>=0;i--) 28 { 29 p->have[x >> i & 1][i]++; 30 } 31 p->sz = 1; p->sum = x; return ; 32 } 33 int m = ((x>>dep) & 1); 34 if(p->ch[m] == NULL) 35 { 36 p->ch[m] = getnew(); 37 } 38 insert(p->ch[m], dep-1, x); 39 int szl = p->ch[0] ? p->ch[0]->sz : 0; 40 int szr = p->ch[1] ? p->ch[1]->sz : 0; 41 p->sz = szl + szr; 42 ll suml = p->ch[0] ? p->ch[0]->sum : 0; 43 ll sumr = p->ch[1] ? p->ch[1]->sum : 0; 44 p->sum = suml + sumr; 45 // 46 //p->have[m][dep] ++; 47 for(int i=20;i>=0;i--) 48 { 49 p->have[0][i] = p->have[1][i] = 0; 50 if(p->ch[0]) p->have[0][i] += p->ch[0]->have[0][i], p->have[1][i] += p->ch[0]->have[1][i]; 51 if(p->ch[1]) p->have[0][i] += p->ch[1]->have[0][i], p->have[1][i] += p->ch[1]->have[1][i]; 52 } 53 54 /*if(x == 5 && dep == 2) 55 { 56 printf("%d ---- %d\n",p->have[0][2], p->have[1][2]); 57 }*/ 58 } 59 void down(node *p, int dep) 60 { 61 if(dep == -1) 62 { 63 p->sum ^= p->lazy; 64 p->lazy = 0; 65 return ; 66 } 67 for(int i=0;i<2;i++) 68 { 69 if(p->ch[i]) p->ch[i]->lazy ^= p->lazy; 70 } 71 if((p->lazy >> dep) & 1) 72 { 73 /*if(p->ch[0]) 74 { 75 p->ch[0]->sum += (1<<dep) * p->ch[0]->sz; 76 } 77 if(p->ch[1]) 78 { 79 p->ch[1]->sum -= (1<<dep) * p->ch[1]->sz; 80 }*/ 81 swap(p->ch[0], p->ch[1]); 82 } 83 //ll suml = p->ch[0] ? p->ch[0]->sum : 0; 84 //ll sumr = p->ch[1] ? p->ch[1]->sum : 0; 85 //p->sum = suml + sumr; 86 for(int i=20;i>=0;i--) 87 { 88 if(p->lazy >> i & 1) 89 { 90 p->sum += p->have[0][i] * (1<<i) - p->have[1][i] * (1<<i); 91 swap(p->have[0][i], p->have[1][i]); 92 } 93 } 94 p->lazy = 0; 95 } 96 /*void solve() 97 { 98 node *p = root; 99 int ans = 0; 100 for(int i=20;i>=0;i--) 101 { 102 down(p, i); 103 if(p->ch[0] && p->ch[0]->sz == (1<<i+1) - 1) 104 { 105 ans |= (1<<i); 106 p = p->ch[1]; 107 } 108 else 109 { 110 p = p->ch[0]; 111 } 112 if(!p) break; 113 } 114 printf("%d\n",ans); 115 }*/ 116 ll query(node *p, int k, int dep) 117 { 118 down(p, dep); 119 if(p->ch[0] == NULL) return query(p->ch[1], k, dep-1); 120 //if(dep) 121 { 122 if(p->ch[0]) down(p->ch[0], dep-1); 123 if(p->ch[1]) down(p->ch[1], dep-1); 124 } 125 int szl = p->ch[0]->sz; 126 //if(dep == 0 && k == 1) printf("%lld %lld ====== %lld\n",p->sum,p->ch[0]->sum, p->ch[1]->sum); 127 if(k == szl) 128 { 129 return p->ch[0]->sum; 130 } 131 if(k < szl) return query(p->ch[0], k, dep-1); 132 else 133 { 134 // if(dep) down(p->ch[0], dep-1); 135 // if(dep == 2) printf("%lld ????? %d \n",p->ch[0]->sum,szl); 136 return p->ch[0]->sum + query(p->ch[1], k-szl, dep-1); 137 } 138 } 139 140 map<int, int> mp; 141 int a[N], b[N]; 142 int main() 143 { 144 cin >> n >> m; 145 root = getnew(); 146 for(int i=1;i<=n;i++) 147 { 148 int x; scanf("%d",&x); 149 //if(mp[x]) continue; 150 insert(root, 20, x); 151 //mp[x] = 1; 152 a[i] = x; 153 } 154 while(m--) 155 { 156 int x, k; scanf("%d%d",&x,&k); 157 root->lazy ^= x; 158 printf("%lld -- ",query(root,k,20)); 159 for(int i=1;i<=n;i++) {a[i]^=x; b[i] = a[i];} 160 for(int i=1;i<=n;i++) printf("%d# ",a[i]); puts(""); 161 sort(b+1,b+1+n); 162 ll ans = 0; 163 for(int i=1;i<=k;i++) ans += b[i]; 164 printf("%lld\n",ans); 165 } 166 return 0; 167 } 168 /* 169 5 100 170 45 69 47 52 12 171 172 */
以上是关于CodeForeces 842d Vitya and Strange Lesson ——(带lazy标记的01字典树)的主要内容,如果未能解决你的问题,请参考以下文章
codeforces 842D Vitya and Strange Lesson