[SPOJ IITWPC4F Gopu and the Grid Problem]线段树区间翻转
知识点:data structure
segment tree
1. 题目链接
[SPOJ IITWPC4F Gopu and the Grid Problem]
2. 题意描述
在一个二维
X−Y
平面
(0≤x,y≤100000)
上有三种操作。操作次数为
q
。
-
-
y l r
表示翻转
y
坐标在
-
q x0 y0 x1 y1
表示求一个子矩阵中
1
的个数,子矩阵中所有的点满足
3. 解题思路
一拿到题目,直接就是二维线段树。但是一看数据范围不对。那就细想一下,这个操作比较特殊,修改操作都是针对一整行,或者一整列的,实际上,就是相当于一个一维的操作。所以可以用两个线段树,互斥地分别处理行和列的修改操作,并分别维护行和列中,区间为
1
的个数即可。
我们设行
但是查询又是二维的。所以需要将行列查询合并。因为行列的操作是异或的。所以查询的答案,就应该是
不懂的话在纸上比划比划就知道了。
4. 实现代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 100000 + 5;
int q;
template<class T>
struct Seg {
T sum[MAXN << 2]; // 标记的行数/列数
bool tag[MAXN << 2];
void init() {
memset(sum, 0, sizeof(sum));
memset(tag, 0, sizeof(tag));
}
inline void pushUp(int& rt) { sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; }
inline void pushDw(const int& w, int& rt) {
if(tag[rt]) {
sum[rt << 1] = (w - (w >> 1)) - sum[rt << 1];
sum[rt << 1 | 1] = (w >> 1) - sum[rt << 1 | 1];
tag[rt << 1] ^= 1;
tag[rt << 1 | 1] ^= 1;
tag[rt] = false;
}
}
void update(int& L, int& R, int l, int r, int rt) {
if(L <= l && r <= R) {
tag[rt] ^= 1;
sum[rt] = (r - l + 1) - sum[rt];
return;
}
int mid = (l + r) >> 1;
pushDw(r - l + 1, rt);
if(L <= mid) update(L, R, l, mid, rt << 1);
if(R > mid) update(L, R, mid + 1, r, rt << 1 | 1);
pushUp(rt);
}
T query(int& L, int& R, int l, int r, int rt) {
if(L <= l && r <= R) return sum[rt];
int mid = (l + r) >> 1; T ret = 0;
pushDw(r - l + 1, rt);
if(L <= mid) ret += query(L, R, l, mid, rt << 1);
if(R > mid) ret += query(L, R, mid + 1, r, rt << 1 | 1);
return ret;
}
};
Seg<int> row, col;
int main() {
#ifdef ___LOCAL_WONZY___
freopen("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
char op[5];
int l, r, x[2], y[2];
int n = MAXN;
while(~scanf("%d", &q)) {
row.init(); col.init();
while(q --) {
scanf("%s", op);
if(op[0] == 'q') {
scanf("%d %d %d %d", &x[0], &y[0], &x[1], &y[1]); ++ x[0], ++ x[1], ++ y[0], ++ y[1];
int nr = row.query(x[0], x[1], 1, n, 1);
int nc = col.query(y[0], y[1], 1, n, 1);
LL ans = (LL)nr * (y[1] - y[0] + 1) + (LL)nc * (x[1] - x[0] + 1) - 2LL * nr * nc;
printf("%lld\n", ans);
continue;
}
scanf("%d %d", &l, &r); ++ l, ++ r;
if(op[0] == 'x') {
row.update(l, r, 1, n, 1);
} else {
col.update(l, r, 1, n, 1);
}
}
}
return 0;
}