[FZU 2105 Digits Count] 线段树区间复合操作
题目链接:
[FZU 2105 Digits Count]
题意描述:给定N个数。每个数在[0, 15] 范围内。(1 <= N <= 1000000)有四种区间操作:
- AND opn L, R 表示区间[L, R] 的所有数字与opn 进行与操作
- OR opn L, R 表示区间[L, R] 的所有数字与opn 进行或操作
- XOR opn L, R 表示区间[L, R] 的所有数字与opn 进行异或操作
- SUM L,R 求区间[L, R] 的所有数字之和
0 <=opn <= 15
解题思路:很不错的一道线段树。四个二进制位能够表示出每个数字。然后可以用四个线段树分别维护每一位在区间[L, R] 的1 的个数,把每一位单独拿出来这样就很方便进行位运算操作了。与 0 操作就相当于区间置0, 或1 操作就相当于区间置1, 异或1 操作就相当于区间翻转(0变1, 1 变0)。求出每一位在区间[L, R] 的个数, 很容易就可以得到答案了。
但是要注意一下, 在这里要考虑一下位运算的先后顺序。
比如:
(x | 1) ^ 1 = 1 ^ 1 = x & 0, BUT, (x ^ 1) | 1 = x | 1;(x & 0) ^ 1 = 0 ^ 1 = x | 1, BUT, (x ^ 1) & 0 = x & 0;
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w",stdout)
#define fst first
#define snd second
#define lson l, mid, (rt << 1)
#define rson mid + 1, r, (rt << 1 | 1)
typedef __int64 LL;
//typedef long long LL;
typedef pair<int, int> PII;
const int MAXN = 1000000 + 5;
template <class T>
inline bool scan_d (T &ret) {
char c;
int sgn;
if (c = getchar(), c == EOF) return 0; //EOF
while (c != '-' && (c < '0' || c > '9') ) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
struct Seg {
struct SNode {
int sum;
bool tag[3];
} node[MAXN << 2];
void init() {
memset (node, 0, sizeof (node) );
}
inline void pushUp (int rt) {
node[rt].sum = node[rt << 1].sum + node[rt << 1 | 1].sum;
}
inline void pushDown (int w, int rt) {
if (node[rt].tag[2]) {
if (node[rt << 1].tag[0]) {
/// (x & 0) ^ 1 => 0 ^ 1 => x | 1
node[rt << 1].tag[0] = 0;
node[rt << 1].tag[1] = 1;
node[rt << 1].sum = w - (w >> 1);
} else if (node[rt << 1].tag[1]) {
/// (x | 1) ^ 1 = 1 ^ 1 = x & 0
node[rt << 1].tag[0] = 1;
node[rt << 1].tag[1] = 0;
node[rt << 1].sum = 0;
} else {
node[rt << 1].tag[2] ^= 1;
node[rt << 1].sum = w - (w >> 1) - node[rt << 1].sum;
}
if (node[rt << 1 | 1].tag[0]) {
/// (x & 0) ^ 1 => 0 ^ 1 => x | 1
node[rt << 1 | 1].tag[0] = 0;
node[rt << 1 | 1].tag[1] = 1;
node[rt << 1 | 1].sum = (w >> 1);
} else if (node[rt << 1 | 1].tag[1]) {
/// (x | 1) ^ 1 = 1 ^ 1 = x & 0
node[rt << 1 | 1].tag[0] = 1;
node[rt << 1 | 1].tag[1] = 0;
node[rt << 1 | 1].sum = 0;
} else {
node[rt << 1 | 1].tag[2] ^= 1;
node[rt << 1 | 1].sum = (w >> 1) - node[rt << 1 | 1].sum;
}
node[rt].tag[2] = 0;
}
if (node[rt].tag[0]) {
node[rt << 1].sum = node[rt << 1 | 1].sum = 0;
node[rt << 1].tag[0] = node[rt << 1 | 1].tag[0] = 1;
node[rt << 1].tag[1] = node[rt << 1 | 1].tag[1] = 0;
node[rt << 1].tag[2] = node[rt << 1 | 1].tag[2] = 0;
node[rt].tag[0] = 0;
}
if (node[rt].tag[1]) {
node[rt << 1].sum = w - (w >> 1);
node[rt << 1 | 1].sum = w >> 1;
node[rt << 1].tag[0] = node[rt << 1 | 1].tag[0] = 0;
node[rt << 1].tag[1] = node[rt << 1 | 1].tag[1] = 1;
node[rt << 1].tag[2] = node[rt << 1 | 1].tag[2] = 0;
node[rt].tag[1] = 0;
}
}
int query (int L, int R, int l, int r, int rt) {
if (L <= l && r <= R) {
return node[rt].sum;
}
int mid = (l + r) >> 1, ret = 0;
pushDown (r - l + 1, rt);
if (L <= mid) ret = query (L, R, lson);
if (R > mid) ret += query (L, R, rson);
return ret;
}
/// AND
void update1 (int L, int R, int l, int r, int rt) {
if (L <= l && r <= R) {
node[rt].sum = 0;
node[rt].tag[0] = 1;
node[rt].tag[1] = 0;
node[rt].tag[2] = 0;
return;
}
pushDown (r - l + 1, rt);
int mid = (l + r) >> 1;
if (L <= mid) update1 (L, R, lson);
if (R > mid) update1 (L, R, rson);
pushUp (rt);
}
/// OR
void update2 (int L, int R, int l, int r, int rt) {
if (L <= l && r <= R) {
node[rt].sum = r - l + 1;
node[rt].tag[0] = 0;
node[rt].tag[1] = 1;
node[rt].tag[2] = 0;
return;
}
int mid = (l + r) >> 1;
pushDown (r - l + 1, rt);
if (L <= mid) update2 (L, R, lson);
if (R > mid) update2 (L, R, rson);
pushUp (rt);
}
/// XOR
void update3 (int L, int R, int l, int r, int rt) {
if (L <= l && r <= R) {
node[rt].tag[2] ^= 1;
node[rt].sum = (r - l + 1) - node[rt].sum;
if (node[rt].tag[0] && node[rt].tag[2]) {
/// (x & 0) ^ 1 => 0 ^ 1 => x | 1
node[rt].tag[0] = 0;
node[rt].tag[1] = 1;
node[rt].tag[2] = 0;
node[rt].sum = r - l + 1;
} else if (node[rt].tag[1] && node[rt].tag[2]) {
/// (x | 1) ^ 1 = 1 ^ 1 = x & 0
node[rt].tag[0] = 1;
node[rt].tag[1] = 0;
node[rt].tag[2] = 0;
node[rt].sum = 0;
}
return;
}
int mid = (l + r) >> 1;
pushDown (r - l + 1, rt);
if (L <= mid) update3 (L, R, lson);
if (R > mid) update3 (L, R, rson);
pushUp (rt);
}
} seg[4];
void build (int l, int r, int rt) {
if (l == r) {
int x, y;
scan_d (x);
for (int i = 0; i < 4; i ++) {
y = x & (1 << i);
if (y) seg[i].node[rt].sum = 1;
}
return;
}
int mid = (l + r) >> 1;
build (lson);
build (rson);
for (int i = 0; i < 4; i++) {
seg[i].pushUp (rt);
}
}
int T, N, M;
int res;
char buf[15];
int main() {
#ifndef ONLINE_JUDGE
FIN;
// FOUT;
#endif // ONLINE_JUDGE
int L, R, v;
scan_d (T);
while (T --) {
scan_d (N);
scan_d (M);
for (int i = 0; i < 4; i++) {
seg[i].init();
}
build (1, N, 1);
while (M --) {
scanf ("%s", buf);
switch (buf[0]) {
case 'A':
scan_d (v);
scan_d (L);
scan_d (R);
L ++, R ++;
for (int i = 0; i < 4; i++) {
int x = v & (1 << i);
if (!x) {
seg[i].update1 (L, R, 1, N, 1);
}
}
break;
case 'O':
scan_d (v);
scan_d (L);
scan_d (R);
L ++, R ++;
for (int i = 0; i < 4; i++) {
int x = v & (1 << i);
if (x) {
seg[i].update2 (L, R, 1, N, 1);
}
}
break;
case 'X':
scan_d (v);
scan_d (L);
scan_d (R);
L ++, R ++;
for (int i = 0; i < 4; i++) {
int x = v & (1 << i);
if (x) {
seg[i].update3 (L, R, 1, N, 1);
}
}
break;
case 'S':
scan_d (L);
scan_d (R);
L ++, R ++;
res = 0;
for (int i = 3; i >= 0; i--) {
int x;
x = seg[i].query (L, R, 1, N, 1);
res = (res << 1) + x;
}
printf ("%d\n", res);
break;
}
}
}
return 0;
}