给一个序列,每次操作对这个序列中的所有数异或一个x,问每次操作完以后整个序列的mex值。

  做法是去重后构建01字典树,异或x就是对root加一个x的lazy标志,每次pushDown时如果lazy的这一位是1,则交换左右儿子。找mex的话只要每次往左走,如果左子树是满的,则往右走,并且加上左边相应造成的贡献。具体见代码:

 #include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + ;
typedef long long ll; int n, m;
struct node
{
int sz, lazy;
node* ch[];
void init() {sz = ; lazy = ; ch[] = ch[] = NULL;}
}nodes[N<<], *root;
int tot; node* getnew()
{
node *p = &nodes[tot++];
p->init();
return p;
}
void insert(node *p, int dep, int x)
{
if(dep == -) return ;
int m = ((x>>dep) & );
if(p->ch[m] == NULL)
{
p->ch[m] = getnew();
}
insert(p->ch[m], dep-, x);
int szl = p->ch[] ? p->ch[]->sz : ;
int szr = p->ch[] ? p->ch[]->sz : ;
p->sz = szl + szr + ;
}
void down(node *p, int dep)
{
for(int i=;i<;i++)
{
if(p->ch[i]) p->ch[i]->lazy ^= p->lazy;
}
if((p->lazy >> dep) & ) swap(p->ch[], p->ch[]);
p->lazy = ;
}
void solve()
{
node *p = root;
int ans = ;
for(int i=;i>=;i--)
{
down(p, i);
if(p->ch[] && p->ch[]->sz == (<<i+) - )
{
ans |= (<<i);
p = p->ch[];
}
else
{
p = p->ch[];
}
if(!p) break;
}
printf("%d\n",ans);
} map<int, int> mp;
int main()
{
cin >> n >> m;
root = getnew();
for(int i=;i<=n;i++)
{
int x; scanf("%d",&x);
if(mp[x]) continue;
insert(root, , x);
mp[x] = ;
}
while(m--)
{
int x; scanf("%d",&x);
root->lazy ^= x;
solve();
}
return ;
}

  还有一个类似的题目,之前青岛场的热身赛,每次需要求的是前k小的和。具体的做法类似,求和时如果左边的sz比k小则直接加上左边的sum并且向右边递归即可。这里需要注意,到当前节点是,如果要求其子树的sum,需要先对其子树进行pushDown,因为其sum已经在其子树要进行交换儿子的时候发生变化了,因此每次pushDown维护sum时需要用log次暴力地算出现在的sum,那么就需要对每个节点维护一个have数组,来记录各位上0和1的位数。具体见代码(含暴力对拍):

 #include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + ;
typedef long long ll; int n, m;
struct node
{
int sz, lazy;
ll sum;
node* ch[];
int have[][];
void init() {sz = ; lazy = ; sum = ; ch[] = ch[] = NULL; memset(have, , sizeof have);}
}nodes[N<<], *root;
int tot; node* getnew()
{
node *p = &nodes[tot++];
p->init();
return p;
}
void insert(node *p, int dep, int x)
{
if(dep == -)
{
for(int i=;i>=;i--)
{
p->have[x >> i & ][i]++;
}
p->sz = ; p->sum = x; return ;
}
int m = ((x>>dep) & );
if(p->ch[m] == NULL)
{
p->ch[m] = getnew();
}
insert(p->ch[m], dep-, x);
int szl = p->ch[] ? p->ch[]->sz : ;
int szr = p->ch[] ? p->ch[]->sz : ;
p->sz = szl + szr;
ll suml = p->ch[] ? p->ch[]->sum : ;
ll sumr = p->ch[] ? p->ch[]->sum : ;
p->sum = suml + sumr;
//
//p->have[m][dep] ++;
for(int i=;i>=;i--)
{
p->have[][i] = p->have[][i] = ;
if(p->ch[]) p->have[][i] += p->ch[]->have[][i], p->have[][i] += p->ch[]->have[][i];
if(p->ch[]) p->have[][i] += p->ch[]->have[][i], p->have[][i] += p->ch[]->have[][i];
} /*if(x == 5 && dep == 2)
{
printf("%d ---- %d\n",p->have[0][2], p->have[1][2]);
}*/
}
void down(node *p, int dep)
{
if(dep == -)
{
p->sum ^= p->lazy;
p->lazy = ;
return ;
}
for(int i=;i<;i++)
{
if(p->ch[i]) p->ch[i]->lazy ^= p->lazy;
}
if((p->lazy >> dep) & )
{
/*if(p->ch[0])
{
p->ch[0]->sum += (1<<dep) * p->ch[0]->sz;
}
if(p->ch[1])
{
p->ch[1]->sum -= (1<<dep) * p->ch[1]->sz;
}*/
swap(p->ch[], p->ch[]);
}
//ll suml = p->ch[0] ? p->ch[0]->sum : 0;
//ll sumr = p->ch[1] ? p->ch[1]->sum : 0;
//p->sum = suml + sumr;
for(int i=;i>=;i--)
{
if(p->lazy >> i & )
{
p->sum += p->have[][i] * (<<i) - p->have[][i] * (<<i);
swap(p->have[][i], p->have[][i]);
}
}
p->lazy = ;
}
/*void solve()
{
node *p = root;
int ans = 0;
for(int i=20;i>=0;i--)
{
down(p, i);
if(p->ch[0] && p->ch[0]->sz == (1<<i+1) - 1)
{
ans |= (1<<i);
p = p->ch[1];
}
else
{
p = p->ch[0];
}
if(!p) break;
}
printf("%d\n",ans);
}*/
ll query(node *p, int k, int dep)
{
down(p, dep);
if(p->ch[] == NULL) return query(p->ch[], k, dep-);
//if(dep)
{
if(p->ch[]) down(p->ch[], dep-);
if(p->ch[]) down(p->ch[], dep-);
}
int szl = p->ch[]->sz;
//if(dep == 0 && k == 1) printf("%lld %lld ====== %lld\n",p->sum,p->ch[0]->sum, p->ch[1]->sum);
if(k == szl)
{
return p->ch[]->sum;
}
if(k < szl) return query(p->ch[], k, dep-);
else
{
// if(dep) down(p->ch[0], dep-1);
// if(dep == 2) printf("%lld ????? %d \n",p->ch[0]->sum,szl);
return p->ch[]->sum + query(p->ch[], k-szl, dep-);
}
} map<int, int> mp;
int a[N], b[N];
int main()
{
cin >> n >> m;
root = getnew();
for(int i=;i<=n;i++)
{
int x; scanf("%d",&x);
//if(mp[x]) continue;
insert(root, , x);
//mp[x] = 1;
a[i] = x;
}
while(m--)
{
int x, k; scanf("%d%d",&x,&k);
root->lazy ^= x;
printf("%lld -- ",query(root,k,));
for(int i=;i<=n;i++) {a[i]^=x; b[i] = a[i];}
for(int i=;i<=n;i++) printf("%d# ",a[i]); puts("");
sort(b+,b++n);
ll ans = ;
for(int i=;i<=k;i++) ans += b[i];
printf("%lld\n",ans);
}
return ;
}
/*
5 100
45 69 47 52 12 */

  

CodeForeces 842d Vitya and Strange Lesson ——(带lazy标记的01字典树)的更多相关文章

  1. codeforces 842D Vitya and Strange Lesson

    题目大意: 定义mex数为数组中第一个没有出现的非负整数.有m个操作,每个操作有一个x,将数组中所有的元素都异或x,然后询问当前的mex Input First line contains two i ...

  2. Codeforces.842D.Vitya and Strange Lesson(Trie xor)

    题目链接 /* 异或只有两种情况,可以将序列放到01Tire树上做 在不异或的情况下在Tire上查找序列的mex很容易,从高位到低位 如果0位置上数没有满,则向0递归:否则向1 (0位置上的数都满了 ...

  3. 【cf842D】Vitya and Strange Lesson(01字典树)

    D. Vitya and Strange Lesson 题意 数列里有n个数,m次操作,每次给x,让n个数都异或上x.并输出数列的mex值. 题解 01字典树保存每个节点下面有几个数,然后当前总异或的 ...

  4. Codeforces Round #430 (Div. 2) Vitya and Strange Lesson

    D.Vitya and Strange Lesson(字典树) 题意: 给一个长度为\(n\)的非负整数序列,\(m\)次操作,每次先全局异或\(x\),再查询\(mex\) \(1<=n< ...

  5. Codeforces 948 数论推导 融雪前缀和二分check 01字典树带删除

    A. 全部空的放狗 B. 先O(NLOGNLOGN)处理出一个合数质因数中最大的质数是多少 因为p1 x1 x2的关系是 x2是p在x1之上的最小倍数 所以x1的范围是[x2-p+1,x2-1]要使最 ...

  6. Vitya and Strange Lesson CodeForces - 842D 字典树+交换节点

    题意: Today at the lesson Vitya learned a very interesting function - mex. Mex of a sequence of number ...

  7. Codeforces Round #430 D. Vitya and Strange Lesson

    Today at the lesson Vitya learned a very interesting function - mex. Mex of a sequence of numbers is ...

  8. Codeforces Round #430 (Div. 2) D. Vitya and Strange Lesson

    因为抑或,一眼字典树 但是处理起来比较难 #include<iostream> #include<map> #include<iostream> #include& ...

  9. D. Vitya and Strange Lesson Codeforces Round #430 (Div. 2)

    http://codeforces.com/contest/842/problem/D 树 二进制(路径,每个节点代表一位) #include <cstdio> #include < ...

随机推荐

  1. 大型三甲HIS系统最新C#源码医院信息管理系统NET源码门诊住院医嘱药房药库发药管理源码

    查看医疗信息管理his系统演示 本云his系统源码,适用在县乡一体化,医联体分级诊疗项目上,本源码开发语言asp.net c#,数据库sqlserver2012,开发工具vs2015.技术框架mvc. ...

  2. MQ相关

    1. 如何保证消息按顺序执行 2. 如何保证消息不重复消费 3. 如何保证消息不丢失 4.RabbitMQ Java Client简单生产者.消费者代码示例

  3. kubernetes第八章--NFS PersistentVolume

  4. JAVA基础之Servlet

    个人理解: servlet是用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容.需要注意的在创建的服务器端的目录和实际上存在差别的,并且访 ...

  5. SQL 基本概念、通用语法与分类

    一.SQL 概念  1.什么是 SQL Structured  Query Language 结构化查询语句 2.SQL 作用 (1)是一种所有关系型数据库的查询规范,不同的数据库都支持. (2)通用 ...

  6. SpringBoot+SpringCloud+vue+Element开发项目——集成Swagger文档

    在pom.xml文件中添加Maven依赖 <!--swagger--> <dependency> <groupId>io.springfox</groupId ...

  7. es5中变量提升的问题

    <script> //变量提升的问题 var tem=new Date(); //函数f 输出tem var命令会发生“变量提升”现象 //局部变量优先高于全局变量 var tem=&qu ...

  8. Linux Shell 小数比较

    #!/bin/bash #######expr 方法是错误的,在比较相同位数时可以,当位数不同就会出错,如100.00>70.00就会得出错误的结果 a=123b=123c=99.99rat=` ...

  9. Python——2x和3x的区别汇总

    1. 初始解释器编码: 2x:ascii 编码(不自持中文) 3x:unicode编码 推荐全部更换为utf-8 2. 输出方式不同 2x:print ‘你好’2.7版本的两种都支持 3x:print ...

  10. Android笔记(六十二)网络框架volley

    什么是Volley 很多时候,我们的APP都需要用到网络技术,使用HTTP协议来发送接收数据,谷歌推出了一个网络框架——volley,该框架适合进行数据量不大,但通信频繁的网络操作. 它的优点: (1 ...