原题传送门

本题大意:给定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相信大家都懂了,本来讲之前本人还不怎么懂。。。。。结果讲完就懂了。。。舒服

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. #define mid ((l + r) >> 1)
  5. using namespace std;
  6.  
  7. typedef long long ll;
  8.  
  9. const int maxn = + ;
  10.  
  11. ll segment_tree[][maxn << ], lazy_lable[maxn << ];
  12.  
  13. int n, m, x;
  14.  
  15. void push_up(int k) {
  16. for(int i = ; i < ; i ++) {
  17. segment_tree[i][k] = segment_tree[i][k << ] + segment_tree[i][k << | ];
  18. }
  19. }
  20.  
  21. void push_down(int k, int son) {
  22. if(lazy_lable[k]) {
  23. lazy_lable[k << ] ^= lazy_lable[k];
  24. lazy_lable[k << | ] ^= lazy_lable[k];
  25. for(int i = ; i < ; i ++) {
  26. if((lazy_lable[k] >> i) & ) {
  27. segment_tree[i][k << ] = son - (son >> ) - segment_tree[i][k << ];
  28. segment_tree[i][k << | ] = (son >> ) - segment_tree[i][k << | ];
  29. }
  30. }
  31. lazy_lable[k] = ;
  32. }
  33. }
  34.  
  35. void build(int l, int r, int k) {
  36. if(l == r) {
  37. scanf("%d", &x);
  38. for(int i = ; i < ; i ++) {
  39. if((x >> i) & )
  40. segment_tree[i][k] = ;
  41. }
  42. return;
  43. }
  44. build(l, mid, k << );
  45. build(mid + , r, k << | );
  46. push_up(k);
  47. }
  48.  
  49. void update(int L, int R, int x, int l, int r, int k) {
  50. if(L <= l && R >= r) {
  51. lazy_lable[k] ^= x;
  52. for(int i = ; i < ; i ++) {
  53. if((x >> i) & ) {
  54. segment_tree[i][k] = r - l + - segment_tree[i][k];
  55. }
  56. }
  57. return;
  58. }
  59. push_down(k, r - l + );
  60. if(L <= mid) update(L, R, x, l, mid, k << );
  61. if(R > mid) update(L, R, x, mid + , r, k << | );
  62. push_up(k);
  63. }
  64.  
  65. ll query(int L, int R, int l, int r, int k) {
  66. if(L <= l && R >= r) {
  67. ll cnt = ;
  68. for(int i = ; i < ; i ++) {
  69. cnt += segment_tree[i][k] << i;
  70. }
  71. return cnt;
  72. }
  73. push_down(k, r - l + );
  74. ll ans = ;
  75. if(L <= mid) ans += query(L, R, l, mid, k << );
  76. if(R > mid) ans += query(L, R, mid + , r, k << | );
  77. return ans;
  78. }
  79.  
  80. int main() {
  81. int op, l, r, x;
  82. scanf("%d", &n);
  83. build(, n, );
  84. scanf("%d", &m);
  85. while(m --) {
  86. scanf("%d", &op);
  87. if(op == ) {
  88. scanf("%d %d", &l, &r);
  89. printf("%lld\n", query(l, r, , n, ));
  90. } else {
  91. scanf("%d %d %d", &l, &r, &x);
  92. update(l, r, x, , n, );
  93. }
  94. }
  95. return ;
  96. }

XOR on segment(线段树区间异或更新)的更多相关文章

  1. 洛谷 P2574 XOR的艺术(线段树 区间异或 区间求和)

    To 洛谷.2574 XOR的艺术 题目描述 AKN觉得第一题太水了,不屑于写第一题,所以他又玩起了新的游戏.在游戏中,他发现,这个游戏的伤害计算有一个规律,规律如下 1. 拥有一个伤害串为长度为n的 ...

  2. codeforces 22E XOR on Segment 线段树

    题目链接: http://codeforces.com/problemset/problem/242/E E. XOR on Segment time limit per test 4 seconds ...

  3. codeforces 242E. XOR on Segment 线段树

    题目链接 给n个数, 两种操作, 一种是求区间内的数的和, 一种是将区间内的数异或x. 异或x没有什么思路, 单个异或肯定超时, 区间异或也没有办法做....后来才知道可以按位建线段树, 这样建20棵 ...

  4. 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. 这题 ...

  5. 洛谷 P4513 小白逛公园-区间最大子段和-分治+线段树区间合并(单点更新、区间查询)

    P4513 小白逛公园 题目背景 小新经常陪小白去公园玩,也就是所谓的遛狗啦… 题目描述 在小新家附近有一条“公园路”,路的一边从南到北依次排着nn个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩 ...

  6. HDU 2795 线段树区间最大值,单点更新+二分

    Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  7. hdu 1116 敌兵布阵 线段树 区间求和 单点更新

    线段树的基本知识可以先google一下,不是很难理解 线段树功能:update:单点增减 query:区间求和 #include <bits/stdc++.h> #define lson ...

  8. HDU 1394:Minimum Inversion Number(线段树区间求和单点更新)

    http://acm.hdu.edu.cn/showproblem.php?pid=1394 Minimum Inversion Number Problem Description   The in ...

  9. hdu 3308 线段树 区间合并+单点更新+区间查询

    LCIS Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

随机推荐

  1. 理解ext文件系统

    理解ext文件系统 @(0001学习博客) 注意:本文参考骏马金龙的博客,详情请移步浏览 一.一些常见的文件系统 Linux的文件系统: ext2(无日志功能), ext3, ext4, xfs, r ...

  2. less基本用法:持续归纳中

    todo 1,嵌套语法:https://www.w3cschool.cn/less/nested_directives_bubbling.html 简单来说就是可以与html一样去写css,并且会继承 ...

  3. eclipse中取消自动生成的TODO Auto-generated method stub

    我们在实现接口定义的方法.Eclipse往往会自动加上一句:TODO Auto-generated method stub 每次手动删除很麻烦,我们可以设置一下,让强大的Eclipse在完成自动代码时 ...

  4. HTML5 localStorage setItem getItem removeItem

    HTML5 WEB存储中提供了两种客户端的数据存储方法:localStorage 还有sessionStorage localStorage: localStorage 方法存储的数据没有时间限制.第 ...

  5. centos文件实时同步inotify+rsync

    我的应用场景是重要文件备份 端口:873,备份端打开即可 下载地址:https://rsync.samba.org/ftp/rsync/src/ 服务端和客户端要保持版本一致 网盘链接:https:/ ...

  6. 云服务器搭建anaconda pytorch torchvision

    (因为在普通用户上安装有些权限问题安装出错,所以我在root用户下相对容易安装,但是anaconda官网说可以直接在普通用户下安装,不过,在root下安装,其他用户也是能用的. 访问Anaconda官 ...

  7. 32位下操作mongodb心得

    本文出处:http://blog.csdn.net/chaijunkun/article/details/7236911,转载请注明. 随着互联网的变革,互联网的内容生成方式也逐渐地从网站生成转为用户 ...

  8. 一、Smarty安装与调试

    一.安装注:这里所使用的Smarty是3.x版本,要求PHP版本为5.2或者更高.解压下载下来的Smarty压缩文件,将文件夹libs拷到项目中,在项目中引入libs文件夹中的"Smarty ...

  9. 精简版 Selenium PageFactory, Annotation 实例

    精简版 Selenium  PageFactory, Annotation 实例. 先是类: HomePage package com.test;import org.openqa.selenium. ...

  10. 阶段3 2.Spring_03.Spring的 IOC 和 DI_12 注入集合数据

    再复制一份,改名3 常用的注入方式,这里选择set saveAccount方法输出所有的对象 map需要导包 配置xml 集合类型的值配置方式 在property标签里面再写标签 这里选择array. ...