codeforces 242E. XOR on Segment 线段树
2015-12-13 20:01
417 查看
题目链接
给n个数, 两种操作, 一种是求区间内的数的和, 一种是将区间内的数异或x。
异或x没有什么思路, 单个异或肯定超时, 区间异或也没有办法做....后来才知道可以按位建线段树, 这样建20棵线段树就可以。
每一次异或, 对于给定的x, 如果x的第i位是1, 那么就将第i棵线段树在给定的区间内0,1翻转, 这是很基础的操作。
对于区间求和操作, 我们可以求出给定的区间, 从高位到低位, 每一位依次有多少个1, 然后就可以直接求出来, 感觉不好表达....具体看代码。
给n个数, 两种操作, 一种是求区间内的数的和, 一种是将区间内的数异或x。
异或x没有什么思路, 单个异或肯定超时, 区间异或也没有办法做....后来才知道可以按位建线段树, 这样建20棵线段树就可以。
每一次异或, 对于给定的x, 如果x的第i位是1, 那么就将第i棵线段树在给定的区间内0,1翻转, 这是很基础的操作。
对于区间求和操作, 我们可以求出给定的区间, 从高位到低位, 每一位依次有多少个1, 然后就可以直接求出来, 感觉不好表达....具体看代码。
#include<bits/stdc++.h> using namespace std; #define pb(x) push_back(x) #define ll long long #define mk(x, y) make_pair(x, y) #define lson l, m, rt<<1 #define mem(a) memset(a, 0, sizeof(a)) #define rson m+1, r, rt<<1|1 #define mem1(a) memset(a, -1, sizeof(a)) #define mem2(a) memset(a, 0x3f, sizeof(a)) #define rep(i, a, n) for(int i = a; i<n; i++) #define ull unsigned long long typedef pair<int, int> pll; const double PI = acos(-1.0); const double eps = 1e-8; const int mod = 1e9+7; const int inf = 1061109567; const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} }; const int maxn = 1e5+5; int sum[maxn<<2][21], XOR[maxn<<2][21], a[25]; void pushUp(int rt, int pos) { sum[rt][pos] = sum[rt<<1][pos] + sum[rt<<1|1][pos]; } void pushDown(int rt, int m, int pos) { if(XOR[rt][pos]) { sum[rt<<1][pos] = (m-(m>>1)) - sum[rt<<1][pos]; sum[rt<<1|1][pos] = (m>>1)-sum[rt<<1|1][pos]; XOR[rt<<1][pos] ^= 1; XOR[rt<<1|1][pos] ^= 1; XOR[rt][pos] = 0; } } void update(int L, int R, int l, int r, int rt, int pos) { if(L<=l&&R>=r) { XOR[rt][pos] ^= 1; sum[rt][pos] = r-l+1-sum[rt][pos]; return ; } pushDown(rt, r-l+1, pos); int m = l+r>>1; if(L<=m) update(L, R, lson, pos); if(R>m) update(L, R, rson, pos); pushUp(rt, pos); } int query(int L, int R, int l, int r, int rt, int pos) { if(L<=l&&R>=r) { return sum[rt][pos]; } pushDown(rt, r-l+1, pos); int m = l+r>>1, ret = 0; if(L<=m) ret += query(L, R, lson, pos); if(R>m) ret += query(L, R, rson, pos); return ret; } int main() { int n, x, m, y, sign, z; cin>>n; mem(XOR); for(int i = 1; i<=n; i++) { scanf("%d", &x); for(int j = 0; j<21; j++) { if((1<<j)&x) { update(i, i, 1, n, 1, j); } } } cin>>m; while(m--) { scanf("%d", &sign); if(sign==1) { ll tmp = 0; scanf("%d%d", &x, &y); for(int i = 20; i>=0; i--) { tmp = 1ll*tmp*2+query(x, y, 1, n, 1, i); //query是求这个区间里每一位有多少个1 } cout<<tmp<<endl; } else { scanf("%d%d%d", &x, &y, &z); for(int j = 0; j<20; j++) { if(z&(1<<j)) { //如果给出的x第j位是1, 那么就将区间内第j棵线段树翻转 update(x, y, 1, n, 1, j); } } } } return 0; }
相关文章推荐
- eclipse-PyDev和vim简易配置
- 第一眼你能看出这是函数声明吗
- 回溯算法---重点
- Effective C++规定45 附加代码
- 移动页面缩放方法之(三)rem布局
- 第一篇
- 自定义不等高cell的纯代码步骤(frame)
- ListView实现单选(一)
- 真机测试时出现 could not find developer disk image问题
- HDU 1176 免费馅饼
- jQuery之call()方法的使用
- Firefox 的页面缩放选项在这里 - Http Tool 插件查看自动格式化后的 json
- 传统金融和互联网金融
- 关键字const在指针中的运用
- Unity3D -- 打包Android多个AndroidManifest
- syntax error: unexpected :=解决方案
- 编译Chromium Android版本
- 编译Chromium Android版本
- 机器学习: 逻辑回归(Logistic Regression)
- bzoj2142 礼物 组合数学&中国剩余定理