CodeForeces 842d Vitya and Strange Lesson ——(带lazy标记的01字典树)
给一个序列,每次操作对这个序列中的所有数异或一个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字典树)的更多相关文章
- codeforces 842D Vitya and Strange Lesson
题目大意: 定义mex数为数组中第一个没有出现的非负整数.有m个操作,每个操作有一个x,将数组中所有的元素都异或x,然后询问当前的mex Input First line contains two i ...
- Codeforces.842D.Vitya and Strange Lesson(Trie xor)
题目链接 /* 异或只有两种情况,可以将序列放到01Tire树上做 在不异或的情况下在Tire上查找序列的mex很容易,从高位到低位 如果0位置上数没有满,则向0递归:否则向1 (0位置上的数都满了 ...
- 【cf842D】Vitya and Strange Lesson(01字典树)
D. Vitya and Strange Lesson 题意 数列里有n个数,m次操作,每次给x,让n个数都异或上x.并输出数列的mex值. 题解 01字典树保存每个节点下面有几个数,然后当前总异或的 ...
- Codeforces Round #430 (Div. 2) Vitya and Strange Lesson
D.Vitya and Strange Lesson(字典树) 题意: 给一个长度为\(n\)的非负整数序列,\(m\)次操作,每次先全局异或\(x\),再查询\(mex\) \(1<=n< ...
- Codeforces 948 数论推导 融雪前缀和二分check 01字典树带删除
A. 全部空的放狗 B. 先O(NLOGNLOGN)处理出一个合数质因数中最大的质数是多少 因为p1 x1 x2的关系是 x2是p在x1之上的最小倍数 所以x1的范围是[x2-p+1,x2-1]要使最 ...
- Vitya and Strange Lesson CodeForces - 842D 字典树+交换节点
题意: Today at the lesson Vitya learned a very interesting function - mex. Mex of a sequence of number ...
- 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 ...
- Codeforces Round #430 (Div. 2) D. Vitya and Strange Lesson
因为抑或,一眼字典树 但是处理起来比较难 #include<iostream> #include<map> #include<iostream> #include& ...
- D. Vitya and Strange Lesson Codeforces Round #430 (Div. 2)
http://codeforces.com/contest/842/problem/D 树 二进制(路径,每个节点代表一位) #include <cstdio> #include < ...
随机推荐
- Unity UnityWebRequest实现与后端的交互
一般我们与后端对接的时候会用到UnityWebRequest这里简单使用这个与后端进行交互这个是总类 using UnityEngine;using System.Collections;using ...
- grep过滤日志
A -B -C 后面都跟阿拉伯数字 -A是显示匹配后和它后面的n行. -B是显示匹配行和它前面的n行. -C是匹配行和它前后各n行. 总体来说,-C覆盖面最大.用它保险些.哈哈.这3个开关都是关于匹配 ...
- HTML基本代码
HTML 今天回顾html,总结一下今日所学内容. -------------------正文-------------------------- 目的:通过一些基础的标签制作关于LOL的静态网页 所 ...
- SQL*Plus 与数据库的交互(SQL*Plus时什么)
Oracle 的 SQL*Plus 是与数据库进行交互的客户端工具,在 SQL*Plus中,可以运行 SQL*Plus 命令与 SQL*Plus 语句. SQL*Plus 时一个基于 C/S 两层 ...
- android studio 出现 Default Activity not found
1.AndroidManifest.xml <activity android:name=".activity.StartPage" android:screenOrient ...
- C# NPOI Excel 合并单元格和取消单元格
1.合并单元操作 //合并单元格 /** 第一个参数:从第几行开始合并 第二个参数:到第几行结束合并 第三个参数:从第几列开始合并 第四个参数:到第几列结束合并 **/ CellRangeAddres ...
- 实战OpenGLES--iOS平台使用OpenGLES渲染YUV图片
上一篇文章 实战FFmpeg--iOS平台使用FFmpeg将视频文件转换为YUV文件 演示了如何将视频文件转换为yuv文件保存,现在要做的是如何将yuv文件利用OpenGLES渲染展示出图像画面.要将 ...
- Python学习日记(二十五) 接口类、抽象类、多态
接口类 继承有两种用途:继承基类的方法,并且做出自己的改变或扩展(代码重用)和声明某个子类兼容于某基类,定义一个接口类interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子 ...
- Nginx 配置 HTTPS(多域名)
平常开发要求比较低, 依然在用 HTTP, 但到了微信小程序就不行了, 腾讯和苹果都对 API 提出了 HTTPS 的要求. 尤其是苹果, 不仅要求 HTTPS, 还要求 TLS 协议版本要在 1.2 ...
- python面试总结4(算法与内置数据结构)
算法与内置数据结构 常用算法和数据结构 sorted dict/list/set/tuple 分析时间/空间复杂度 实现常见数据结构和算法 数据结构/算法 语言内置 内置库 线性结构 list(列表) ...