这俩题刚好把一维的两种情况扩展到二维去了。
首先是poj 2155,成段更新,求某点的值;
然后是poj 1195,单点更新,求某段的和。
凑齐了二维的两种。
需要注意的是query的方式,要像高数求积分时面积那样的算。
详见代码。
poj 2155:
题意:
给一个N * N的矩阵,然后现在有两种操作。
1.C x1 y1 x2 y2。
2.Q x y。
第一种操作是将 (x1,y1)到(x2,y2)里面的点全部翻转(初始为0,翻转就是1变0,0变1)。
第二种是询问 (x,y)点的状态(为0或者为1)
解析:
用二维的树状数组做,注意这题是从左上角到右下角来建立坐标系的(这是坑啊 容易乱)。
和上一题一样(hdu 1556),这题也是加加减减,更新就行。
难点在于更新的写法。
update(x1, y1, 1);
update(x2 + 1, y1, -1);
update(x1, y2 + 1, -1);
update(x2 + 1, y2 + 1, 1);
先更新左上角,然后多加的往下减,多减的往上加,就行了。
开始的时候没把最后一句的更新加上wa了。
是这组数据测出来的,没加最后一句,会跑出负数。
1
3 10
C 2 1 2 2
Q 2 2
C 2 1 2 1
Q 1 1
C 1 1 2 1
C 1 2 1 2
C 1 1 2 2
Q 1 1
C 1 1 2 1
Q 2 1
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1
using namespace std;
const int maxn = 1000 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
int c[maxn][maxn];
int n, m;
int lowbit(int x)
{
return x & -x;
}
void update(int x, int y, int num)
{
int t = x;
while (y <= n)
{
x = t;
while (x <= n)
{
c[x][y] += num;
x += lowbit(x);
}
y += lowbit(y);
}
}
int query(int x, int y)
{
int res = 0;
int t = x;
while (y)
{
x = t;
while (x)
{
res += c[x][y];
x -= lowbit(x);
}
y -= lowbit(y);
}
return res;
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
int ncase;
scanf("%d", &ncase);
while (ncase--)
{
memset(c, 0, sizeof(c));
scanf("%d%d", &n, &m);
while (m--)
{
char op[2];
scanf("%s", op);
if (op[0] == 'C')
{
int x1, y1, x2, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
update(x1, y1, 1);
update(x2 + 1, y1, -1);
update(x1, y2 + 1, -1);
update(x2 + 1, y2 + 1, 1);
// for (int y = 1; y <= n; y++)
// {
// for (int x = 1; x <= n; x++)
// {
// cout << query(x, y) << " ";
// }
// cout << endl;
// }
// cout << "--------------" << endl;
}
else
{
int x, y;
scanf("%d%d", &x, &y);
if (query(x, y) & 1)
{
printf("1\n");
}
else
{
printf("0\n");
}
}
}
if (ncase)
printf("\n");
}
return 0;
}
poj 1195:
题意:
给一个S * S的矩阵,然后又如下操作:
0 s,表示建立一个 s * s的矩阵;
1 x y a,表示将单点(x,y)加上数a;
2 l b r t,表示询问点(l,b)到点(r,t)各个点的权值和;
3,33333333333333结束这场团战。
解析:
这题是普通的那种坐标系。
注意询问的时候是:
LL ans = query(r, t) - query(l - 1, t) - query(r, b - 1) + query(l - 1, b - 1);
这样算就行了。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1
using namespace std;
const int maxn = 1024 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
LL c[maxn][maxn];
int s;
int lowbit(int x)
{
return x & -x;
}
void update(int x, int y, LL num)
{
int t = x;
while (y <= s)
{
x = t;
while (x <= s)
{
c[x][y] += num;
x += lowbit(x);
}
y += lowbit(y);
}
}
LL query(int x, int y)
{
LL res = 0;
int t = x;
while (y)
{
x = t;
while (x)
{
res += c[x][y];
x -= lowbit(x);
}
y -= lowbit(y);
}
return res;
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
int op;
while (~scanf("%d", &op))
{
if (op == 0)
{
scanf("%d", &s);
memset(c, 0, sizeof(c));
}
if (op == 1)
{
int x, y;
LL a;
scanf("%d%d%lld", &x, &y, &a);
x++, y++;
update(x, y, a);
}
if (op == 2)
{
int l, b, r, t;
scanf("%d%d%d%d", &l, &b, &r, &t);
l++, b++, r++, t++;
LL ans = query(r, t) - query(l - 1, t) - query(r, b - 1) + query(l - 1, b - 1);
printf("%lld\n", ans);
}
if (op == 3)
{
break;
}
}
return 0;
}