##[$POJ$ $2155$ $Matrix$](http://poj.org/problem?id=2155) ### 一、题意描述 楼教主出的题,是二维树状数组非常好的题,还结合了开关问题(开关变化的次数如果为偶数,状态不变,奇数状态相反)。 题意就是给了一个二维的坐标平面,**每个点初始值都是$0$**,然后给一个矩形的区域,对该区域的点的状态进行**反转**。然后在中间插有查询,查该点的状态。  其实,还是对反转次数的一个研究,这里为了能快速的查找一个点的反转次数,加上又是二维,且有区间修改,所以选择二维树状数组进行处理,整个二维数组记录 **前缀和$sum$** 的就是反转的次数。  每反转一次,就对整个矩形区间进行修改,反转次数加$1$,最终查询的时候就是查一共反转了多少次,记得取余$2$,如果是偶数,就不变,是奇数,就变$1$。 ### 二、一维数组实现 ```cpp {.line-numbers} #include using namespace std; const int N = 11; int a[N] = {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //树状数组模板 int tr[N]; #define lowbit(x) (x & -x) void add(int x, int c) { for (int i = x; i <= N; i += lowbit(i)) tr[i] += c; } int sum(int x) { int res = 0; for (int i = x; i; i -= lowbit(i)) res += tr[i]; return res; } void print() { for (int i = 1; i < N; i++) cout << sum(i) % 2 << " "; cout << "\n"; } int main() { //记录基数组到树状数组中 for (int i = 1; i < N; i++) add(i, a[i]); // 将2-4取反 add(2, 1), add(4 + 1, -1); print(); //将2-4再取一次反 add(2, 1), add(4 + 1, -1); print(); //将3-4再取一次反 add(3, 1), add(4 + 1, -1); print(); return 0; } /* 输出: 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 */ ``` 拓展到二维就涉及了一下容斥原理,先看一下下图。
注意处理二维树状数组区间更新的时候,假设给的矩形对角线的点为$(x_1,y_1),(x_2,y_2)$。那么更新的时候是: $$\large add(x_1,y_1,v)+add(x_1,y_2+1,-v)+add(x_2,y_1,-v)+add(x_2+1,y_2+1,v)$$ ### 三、二维代码 ```cpp {.line-numbers} #include #include #include const int N = 1010; using namespace std; int n, m; string str; int c[N][N]; #define lowbit(x) (x & -x) void add(int x, int y, int v) { for (int i = x; i < N; i += lowbit(i)) for (int j = y; j < N; j += lowbit(j)) c[i][j] += v; } int sum(int x, int y) { int res = 0; for (int i = x; i; i -= lowbit(i)) for (int j = y; j; j -= lowbit(j)) res += c[i][j]; return res; } int main() { // 加快读入 ios::sync_with_stdio(false), cin.tie(0); int T; cin >> T; while (T--) { memset(c, 0, sizeof(c)); cin >> n >> m; while (m--) { cin >> str; if (str[0] == 'C') { int x1, y1, x2, y2; cin >> x1 >> y1 >> x2 >> y2; // 二维差分 add(x1, y1, 1); add(x2 + 1, y1, -1); add(x1, y2 + 1, -1); add(x2 + 1, y2 + 1, 1); } else { int x, y; cin >> x >> y; printf("%d\n", sum(x, y) % 2); } } if (T) puts(""); } return 0; } ```