知识点:data structure
segment tree
[SPOJ IITWPC4F Gopu and the Grid Problem]
在一个二维 X−Y 平面 (0≤x,y≤100000) 上有三种操作。操作次数为 q 。 (q≤105) 。平面中所有点初始为 0 。
- x l r 表示翻转 x 坐标在 [l,r] 区间中的所有点;
- y l r 表示翻转 y 坐标在 [l,r] 区间中的所有点;
- q x0 y0 x1 y1 表示求一个子矩阵中 1 的个数,子矩阵中所有的点满足 x 坐标在 [x0,x1] 区间, y 坐标在 [y0,y1] 区间。
一拿到题目,直接就是二维线段树。但是一看数据范围不对。那就细想一下,这个操作比较特殊,修改操作都是针对一整行,或者一整列的,实际上,就是相当于一个一维的操作。所以可以用两个线段树,互斥地分别处理行和列的修改操作,并分别维护行和列中,区间为 1 的个数即可。
我们设行 [a,b] 的 1 的个数为 rowab ,列 [c,d] 的 1 的个数是 colcd 。
但是查询又是二维的。所以需要将行列查询合并。因为行列的操作是异或的。所以查询的答案,就应该是
#include
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;
}