给一个序列,每次操作对这个序列中的所有数异或一个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. jQuery.each的function中有哪些参数

    1.没有参数 $("img").each(function(){ $(this).toggleClass("example"); }); 2.有一个参数,这个参 ...

  2. Synopsys DC综合脚本示例

    #****************************************************************************** # File : syn_example ...

  3. robot framework笔记(三):扩展SeleniumLibrary库 (自定义关键字)

    (一)自定义和浏览器相关的关键字 以下代码GitHub 版本库地址: https://github.com/blairwind/blog_rf SeleniumLibrary的扩展文档中提供了3种增加 ...

  4. python智能提取省、市、区地址

    工具原文 https://github.com/DQinYuan/chinese_province_city_area_mapper 说明: https://blog.csdn.net/qq_3325 ...

  5. 利用ssh的用户配置文件config管理ssh会话

    通常利用 ssh 连接远程服务器,一般都要输入以下类似命令: ssh user@hostname -p port 如果拥有多个 ssh 账号,特别是像我这种喜欢在终端里直接 ssh 登陆,不用 PuT ...

  6. 资源管理与调度系统-资源管理系统Mesos

    资源管理与调度系统-资源管理系统Mesos 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Mesos是诞生于UC Berkeley的一个研究项目,它的设计动机是解决编程模型和计算框 ...

  7. 批处理引擎MapReduce程序设计

    批处理引擎MapReduce程序设计 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.MapReduce API Hadoop同时提供了新旧两套MapReduce API,新AP ...

  8. java连接Oracle数据库的操作说明

    在测试中,我们常常需要连接Oracle数据库来进行查询对比.下面,我们就来看看,如何使用java代码来连接数据库,并且取出我们想要的数值. 首先,java中如果要连接Oracle数据库,需要jdbc的 ...

  9. linux网络编程之socket编程(一)

    今天开始,继续来学习linux编程,这次主要是研究下linux下的网络编程,而网络编程中最基本的需从socket编程开始,下面正式开始学习: 什么是socket: 在学习套接口之前,先要回顾一下Tcp ...

  10. SQLyog(MYSQL图形化开发工具)

    安装:下载一个免安装的SQLyog,可以直接使用 使用:输入用户名.密码,点击连接按钮,进行访问MySQL数据库进行操作 在Query窗口中,输入SQL代码,选中要执行的SQL代码,按F8键运行,或按 ...