http://poj.org/problem?id=2155
二维树状数组,其实就是c[maxn][maxn],就是n个一维树状数组,然后,在这一维树状数组里面,再套一个一维树状数组。
所以c[1][1]维护的是第一行的树状数组的前1个,c[1][2]是第一行树状数组的前2个,也就是a[1][1] + a[1][2]。这个和一维bit的定义是一样的。
然后c[2][1]维护的是第一行的bit + 第二行的bit的前1个、也就是a[1][1] + a[2][1],也就是一维树状数组的树状数组
c[2][2]维护的是a[1][1] + a[1][2] + a[2][1] + a[2][2]
然后则题要的是取反,一开始是0,然后运算一次后,变成1,运算两次,又变回0.
这里就发现了,如果运算了奇数次,那就是1,否则是0.所以记录它运算了多少次,看奇偶性就行了。
那么对于一维的情形,在[L, R]运算一次。可以在a[L] + 1,然后a[R + 1] - 1,然后求第i个的话,求一个前缀和就行。就知道操作了多少次,
对于二维。
首先把题目输入的点变化一下,变成左下角 和 右上角。方便处理树状数组。
在a[x1][y1] + 1, a[x1][y2 + 1] - 1,a[x2 + 1][y1] - 1, a[x2 + 1][y2 + 1] - 1
画个图好理解,我也是看题解滴。。。论文有详细证明。
2009 武森:《浅谈信息学竞赛中的“0”和“1”》
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <assert.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> #include <bitset> const int maxn = 1e3 + 20; int c[maxn][maxn]; int n; int lowbit(int x) { return x & (-x); } void add(int x, int y, int val) { for (int i = x; i <= n; i += lowbit(i)) { for (int j = y; j <= n; j += lowbit(j)) { c[i][j] += val; } } } int sum(int x, int y) { int ans = 0; for (int i = x; i >= 1; i -= lowbit(i)) { for (int j = y; j >= 1; j -= lowbit(j)) { ans += c[i][j]; } } return ans; } void work() { memset(c, 0, sizeof c); int q; scanf("%d%d", &n, &q); while (q--) { char str[22]; int x1, y1, x2, y2; scanf("%s", str); if (str[0] == 'C') { scanf("%d%d%d%d", &x1, &y1, &x2, &y2); swap(x1, y1); swap(x2, y2); // swap(y1, y2); add(x1, y1, 1); add(x1, y2 + 1, -1); add(x2 + 1, y1, -1); add(x2 + 1, y2 + 1, -1); } else { scanf("%d%d", &x1, &y1); swap(x1, y1); int res = sum(x1, y1) % 2; if (res != 0) res = 1; printf("%d ", res); } } } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif int t; scanf("%d", &t); while (t--) { work(); if (t) cout << endl; } return 0; }