SMOJ 1980 XOR (线段树)
来源:互联网 发布:淘宝哪里可以买二手货 编辑:程序博客网 时间:2024/05/29 17:11
Solution
这就是棵裸的线段树,我一下就切掉了。话说最近考了好多好多道线duang树啊!感觉我自己都被duang掉了。
由于异或不满足分配律,不能像矩阵那题一样直接对和进行异或操作。而异或是满足结合律的,于是我们可以对于多个异或标记进行合并。
我们抓住异或的本质(别说抓不住),异或x就是如果x二进制的某一位是1,就将被异或的那个数的那一位1变成0,0变成1。我们就在线段树的叶子开一个大小为20左右的数组,记录二进制下每一位是0是1。然后向上维护每一位的和。我们知道一段区间的1个个数就是和,0的个数就是区间长度减去和。我们对这段区间异或x,将x分解,有一位是1,代表将这段区间的每一个数的1变0,0变1,再求和。其实和就变成了区间长度减去和了。于是和就可以进行区间信息加法了。
然后将懒惰标记lazy合并后向下传,和也照样维护,到底端就变成了那一位是0是1了。查询的时候再将对应的位的权乘和累加起来,然后这题就这样的过了。
时间的话,多一个20倍的常数,然而题目良心,操作不多,所以不虚。
ps:这题的数据有毒??我暴力跟正解拍了半天没出错,正解一交AC了,暴力却只有20分,WA了一堆,真是让我长见识了!另外有人的暴力拿了50分,一问,答曰:我的线段树的标记是down到底的,太强大了!我震惊得说不出话来,此处省略rand()+1字。
代码
#include <cstdio>#include <iostream>#include <cstring>#include <cmath>#include <cstdlib>#include <algorithm>#define maxn 100010using namespace std;typedef long long LL;int n, m, a[maxn];struct Tnode{ int num[22]; int lazy;}tree[maxn<<2];void build(int root, int L, int R){ if(L == R){ int temp = a[L], t = 0; while(temp){ tree[root].num[t] = temp & 1; t ++; temp >>= 1; } tree[root].lazy = 0; return; } int mid = (L + R) >> 1, Lson = root << 1, Rson = root << 1 | 1; build(Lson, L, mid); build(Rson, mid+1, R); for(int i = 0; i <= 20; i++) tree[root].num[i] = tree[Lson].num[i] + tree[Rson].num[i]; tree[root].lazy = 0;}void Down(int root, int L, int R){ if(!tree[root].lazy) return; int mid = (L + R) >> 1, Lson = root << 1, Rson = root << 1 | 1; int temp = tree[root].lazy, t = 0; while(temp){ if(temp & 1){ tree[Lson].num[t] = (mid - L + 1) - tree[Lson].num[t]; tree[Rson].num[t] = (R - mid) - tree[Rson].num[t]; } t ++; temp >>= 1; } tree[Lson].lazy ^= tree[root].lazy; tree[Rson].lazy ^= tree[root].lazy; tree[root].lazy = 0;}void update(int root, int L, int R, int x, int y, int v){ if(x > R || y < L) return; if(x <= L && y >= R){ int temp = v, t = 0; while(temp){ if(temp & 1) tree[root].num[t] = (R - L + 1) - tree[root].num[t]; t ++; temp >>= 1; } tree[root].lazy ^= v; return; } Down(root, L, R); int mid = (L + R) >> 1, Lson = root << 1, Rson = root << 1 | 1; update(Lson, L, mid, x, y, v); update(Rson, mid+1, R, x, y, v); for(int i = 0; i <= 20; i++) tree[root].num[i] = tree[Lson].num[i] + tree[Rson].num[i];}LL query(int root, int L, int R, int x, int y){ if(x > R || y < L) return 0LL; if(x <= L && y >= R){ LL ans = 0LL; for(int i = 0; i <= 20; i++) ans += (1LL << i) * tree[root].num[i]; return ans; } Down(root, L, R); int mid = (L + R) >> 1, Lson = root << 1, Rson = root << 1 | 1; LL temp1 = query(Lson, L, mid, x, y); LL temp2 = query(Rson, mid+1, R, x, y); return temp1 + temp2;}int main(){ scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", &a[i]); build(1, 1, n); scanf("%d", &m); int t, l, r, x; for(int i = 1; i <= m; i++){ scanf("%d%d%d", &t, &l, &r); if(t == 1) printf("%lld\n", query(1, 1, n, l, r)); else{ scanf("%d", &x); update(1, 1, n, l, r, x); } } return 0;}
阅读全文
2 0
- SMOJ 1980 XOR (线段树)
- SMOJ 2201 D (线段树)
- hdu 4867 Xor(线段树)
- 【codechef】Nikitosh and xor(线段树)
- Codeforces242E XOR on Segment(线段树)
- [CodeForces242E]XOR on Segment-线段树
- 线段树--codeforces242E XOR on Segment
- 线段树+区间xor+区间求和
- poj 3225【线段树--区间更新,XOR,区间询问】
- CodeForces 242E - XOR on Segment 二维线段树?
- CF 242E XOR on Segment 【线段树】
- CF 242E XOR on Segment(二维线段树)
- Codeforces 242E. XOR on Segment【线段树】
- CodeForces 242E XOR on Segment 二维线段树
- Codeforces 242E XOR on Segment(线段树)
- Codeforecs XOR On Segment 线段树(区间异或,求和)
- CF242:XOR on Segment(线段树区间更新 & 二进制)
- Codeforces 242E- XOR on Segment(线段树)
- 制作2D小游戏 “别踩白块儿”(2最终版)
- 三极管相关知识点释疑(二)
- IO流
- Floyd算法
- LinearLayout——线性布局
- SMOJ 1980 XOR (线段树)
- 【OpenCV】边缘检测:梯度,sobel算子的理解
- 关于基类指针的问题
- 金山笔试题解析
- Linux 初学必备之基础命令篇(二)
- poj 3624 Charm Bracelet
- 线段树
- OpenCv学习笔记(二)--Mat矩阵(图像容器)的创建及CV_8UC1,CV_8UC2等参数详解
- ReactNative基础(三)了解ScrollView并打造一个Banner效果