XOR on segment(线段树区间异或更新)
本题大意:给定n个数字和m个操作,操作共有两种,第一种是求解区间l到r上元素的和,第二种是将区间l到r的元素都异或一个x,作为某个位置的新值。
很容易想到线段树维护区间和,但是我们发现,在区间更新的时候,并没有办法更新,因为我们并不能通过一个区间的和还有我们要异或的值得到这个区间新的异或和,那么我们考虑其他方法。
下面讲述的这个方法,对于值域不大于1 << 20的数据,我们选择用20个数组保存某一个区间k中第 i 位的1的个数,为什么要这么搞呢?
对于第i位,如果区间k的第 i 位原本有s[ i ][ k ]个1,那么对这个区间所有数字都异或一个数字x,我们只需要判断 x 的每一位,如果存在第 i 位为1,那么s[ i ][ k ] = 区间长度 - s[ i ][ k ]。如果第 i 位为0,那么我们忽略这一位。
why ????
0 xor 1 = 1.... 0 xor 0 = 0 也就是说o异或任何值等于任何值。
1 xor 0 = 1.......1 xor 1 = 0 也就是说与1异或之后值变为相反数。所以区间内1的个数就变为了区间中零的个数。
这样我们就可以轻松统计某个区间某一位上有多少个1。query操作相信应该都是明了的。
那么懒惰标记如何处理呢??
当然是用一个数组lazy_lable记录区间k应该往下推的值,如果该值还未下推又来了另一个值需要改变,那么就将这两个值异或起来,多者不限,也就是说只需要一个一维数组来记录每个区间的lazy值就行了。
ok相信大家都懂了,本来讲之前本人还不怎么懂。。。。。结果讲完就懂了。。。舒服
#include <cstdio>
#include <cstring>
#include <algorithm>
#define mid ((l + r) >> 1)
using namespace std; typedef long long ll; const int maxn = + ; ll segment_tree[][maxn << ], lazy_lable[maxn << ]; int n, m, x; void push_up(int k) {
for(int i = ; i < ; i ++) {
segment_tree[i][k] = segment_tree[i][k << ] + segment_tree[i][k << | ];
}
} void push_down(int k, int son) {
if(lazy_lable[k]) {
lazy_lable[k << ] ^= lazy_lable[k];
lazy_lable[k << | ] ^= lazy_lable[k];
for(int i = ; i < ; i ++) {
if((lazy_lable[k] >> i) & ) {
segment_tree[i][k << ] = son - (son >> ) - segment_tree[i][k << ];
segment_tree[i][k << | ] = (son >> ) - segment_tree[i][k << | ];
}
}
lazy_lable[k] = ;
}
} void build(int l, int r, int k) {
if(l == r) {
scanf("%d", &x);
for(int i = ; i < ; i ++) {
if((x >> i) & )
segment_tree[i][k] = ;
}
return;
}
build(l, mid, k << );
build(mid + , r, k << | );
push_up(k);
} void update(int L, int R, int x, int l, int r, int k) {
if(L <= l && R >= r) {
lazy_lable[k] ^= x;
for(int i = ; i < ; i ++) {
if((x >> i) & ) {
segment_tree[i][k] = r - l + - segment_tree[i][k];
}
}
return;
}
push_down(k, r - l + );
if(L <= mid) update(L, R, x, l, mid, k << );
if(R > mid) update(L, R, x, mid + , r, k << | );
push_up(k);
} ll query(int L, int R, int l, int r, int k) {
if(L <= l && R >= r) {
ll cnt = ;
for(int i = ; i < ; i ++) {
cnt += segment_tree[i][k] << i;
}
return cnt;
}
push_down(k, r - l + );
ll ans = ;
if(L <= mid) ans += query(L, R, l, mid, k << );
if(R > mid) ans += query(L, R, mid + , r, k << | );
return ans;
} int main() {
int op, l, r, x;
scanf("%d", &n);
build(, n, );
scanf("%d", &m);
while(m --) {
scanf("%d", &op);
if(op == ) {
scanf("%d %d", &l, &r);
printf("%lld\n", query(l, r, , n, ));
} else {
scanf("%d %d %d", &l, &r, &x);
update(l, r, x, , n, );
}
}
return ;
}
XOR on segment(线段树区间异或更新)的更多相关文章
- 洛谷 P2574 XOR的艺术(线段树 区间异或 区间求和)
To 洛谷.2574 XOR的艺术 题目描述 AKN觉得第一题太水了,不屑于写第一题,所以他又玩起了新的游戏.在游戏中,他发现,这个游戏的伤害计算有一个规律,规律如下 1. 拥有一个伤害串为长度为n的 ...
- codeforces 22E XOR on Segment 线段树
题目链接: http://codeforces.com/problemset/problem/242/E E. XOR on Segment time limit per test 4 seconds ...
- codeforces 242E. XOR on Segment 线段树
题目链接 给n个数, 两种操作, 一种是求区间内的数的和, 一种是将区间内的数异或x. 异或x没有什么思路, 单个异或肯定超时, 区间异或也没有办法做....后来才知道可以按位建线段树, 这样建20棵 ...
- Codeforces Round #149 (Div. 2) E. XOR on Segment (线段树成段更新+二进制)
题目链接:http://codeforces.com/problemset/problem/242/E 给你n个数,m个操作,操作1是查询l到r之间的和,操作2是将l到r之间的每个数xor与x. 这题 ...
- 洛谷 P4513 小白逛公园-区间最大子段和-分治+线段树区间合并(单点更新、区间查询)
P4513 小白逛公园 题目背景 小新经常陪小白去公园玩,也就是所谓的遛狗啦… 题目描述 在小新家附近有一条“公园路”,路的一边从南到北依次排着nn个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩 ...
- HDU 2795 线段树区间最大值,单点更新+二分
Billboard Time Limit: 20000/8000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- hdu 1116 敌兵布阵 线段树 区间求和 单点更新
线段树的基本知识可以先google一下,不是很难理解 线段树功能:update:单点增减 query:区间求和 #include <bits/stdc++.h> #define lson ...
- HDU 1394:Minimum Inversion Number(线段树区间求和单点更新)
http://acm.hdu.edu.cn/showproblem.php?pid=1394 Minimum Inversion Number Problem Description The in ...
- hdu 3308 线段树 区间合并+单点更新+区间查询
LCIS Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
随机推荐
- ng-class的几种用法
参考来自 https://www.cnblogs.com/zhoulin1234/p/9587955.html 方法1.逻辑在后面的中括号里面 ng-class="{true : 'chec ...
- Log4net日志文件自动按月份存放和日志独占问题的解决
让log4net日志文件自动按月份存放 log4net日志文件的作用还真不小,可以保存管理员.用户对数据库的任何操作,保存管理员和用户的登录记录,分析系统运行错误,所以不舍得随便将日志文件Delete ...
- 关系型数据库(七),复杂SQL语句
目录 1.SQL语句由六部分组成 2.Group By 和HAVING 七.复杂SQL语句 1.SQL语句由六部分组成 Select *** From *** Where *** Group B ...
- 序列模式挖掘--SPADE算法
- Linux如何永久打开端口
由于防火墙导致同局域网无法通过IP访问,Linux有多种防火墙,需要查看当前使用的防火墙(开机自启),再进行配置 以下是 iptables 和 firewall 防火墙的相关配置,切忌将自己配置的防 ...
- JSP中解决session超时跳转到登陆页面并跳出iframe框架或局部区域的方法
当session会话超时,页面请求被重新定位到了登陆界面.但登录界面在iframe中的解决方案:在登录页面中加入下面的js代码: <script type="text/javascri ...
- conda install -c anaconda
有些包在conda默认的channels中不包含,比如cudatoolkit-8.0,cudnn等,这时只需要在conda install指令后加上-c anaconda即可.比如要下载cudatoo ...
- Tomcat报错,内存溢出的错误Exception in thread "http-bio-8080-exec-13" java.lang.OutOfMemoryError: PermGen space
说是tomcat 内存溢出,然后按照网上看的搞一搞之后没出息这个问题了 原因是tomcat内存溢出,按照一到五步奏,在第三步加上那段参数.
- java 开发工具包 jdk 64位 jdk-8u221-windows-x64.exe 迅雷下载
迅雷下载链接(迅雷新建任务,复制链接进去): https://download.oracle.com/otn/java/jdk/8u221-b11/230deb18db3e4014bb8e3e8324 ...
- Promise 的使用
Promise 的使用,用于异步处理 ,以及解决地狱回调的: 1. Promise 是一个构造函数,既然是构造函数,我们就可以 new Promise() 就可以得到一个 Promise 的实例 2 ...