• 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
    ",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
    ",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
    ",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
    ",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 
    ",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
    ",ans);
    165     }
    166     return 0;
    167 }
    168 /*
    169 5 100
    170 45 69 47 52 12
    171 
    172 */
    View Code

      

  • 相关阅读:
    软件开发流程(转载)
    SQL_sql的简单查询
    session销毁
    静态数据成员和函数
    word插入图片显示不完整的解决的方法
    【Hibernate步步为营】--复合主键映射具体解释
    android studio 在线更新android sdk,遇到无法Fetching https://dl-ssl.google.com/...的解决方式
    Cisco笔试——2014年
    全局钩子具体解释
    rackup工具
  • 原文地址:https://www.cnblogs.com/zzyDS/p/7819508.html
Copyright © 2020-2023  润新知