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 }
View Code

 

  还有一个类似的题目,之前青岛场的热身赛,每次需要求的是前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 */
View Code

 

  

以上是关于CodeForeces 842d Vitya and Strange Lesson ——(带lazy标记的01字典树)的主要内容,如果未能解决你的问题,请参考以下文章

codeforces 842D Vitya and Strange Lesson

Codeforce842D Vitya and Strange Lesson

cf842D 01字典树|线段树 模板见hdu4825

codeforeces近日题目小结

codeforeces GYM 101142 C

codeforeces近日题目小结