/**
* 二维树状数组(入门):
* 二维树状数组直接上就行了。。。
* 用结构体Line存完输入数据后,按照x从小到大排序。
* 遍历一遍,每次加完crossing数后在更新维护二维树状数组。
* 这类题关键在如何用get_sum(),就是对“面积区间”(按个人理解自己取的名)的正确选取
* 仔细考虑边界情况,是否减一加一。
* 本题:ans += get_sum(lines[i].x - 1, y) - get_sum(lines[i].x, lines[i].y)
* 因为算当前路线(lines[i])与之前路线的交叉口(crossing)时,是之前路线在x之前(不包括x,也就是x-1开始的)
* 和最南边的城市y. 所以要先用(lines[i].x - 1, y) 减去 (lines[i].x - 1, lines[i].y)
* 其他就还有个数据类型要用 __int64的。
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
#define INF 0x7fffffff
#define MAXS 1000005
#define LL __int64
using namespace std;
struct Line {
LL x, y;
bool operator < (const Line &a) const {
return x < a.x;
}
} lines[MAXS];
LL c[1010][1010];
int t, n, m, k;
int lowbit(int x) {
return x & (-x);
}
LL get_sum(int x, int y) {
LL ret = 0;
for(int i = x; i > 0; i -= lowbit(i)) {
for(int j = y; j > 0; j -= lowbit(j)) {
ret += c[j][i];
}
}
return ret;
}
void update(int x, int y) {
for(int i = x; i <= n; i += lowbit(i)) {
for(int j = y; j <= m; j += lowbit(j)) {
c[j][i] ++;
}
}
}
void init(int x, int y) {
for(int i = 1; i <= y; i ++)
for(int j = 1; j <= x; j ++)
c[i][j] = 0;
}
int main()
{
scanf("%d", &t);
for(int curCase = 1; curCase <= t; curCase ++) {
scanf("%d%d%d", &n, &m, &k);
init(n, m);
for(int i = 1; i <= k ;i ++) {
scanf("%I64d%I64d", &lines[i].x, &lines[i].y);
}
sort(lines + 1, lines + k + 1);
LL ans = 0;
for(int i = 1; i <= k; i ++) {
ans += get_sum(lines[i].x - 1, m) - get_sum(lines[i].x - 1, lines[i].y);
update(lines[i].x, lines[i].y);
}
printf("Test case %d: %I64d\n", curCase, ans);
}
return 0;
}
poj 3067 Japan 二维树状数组(入门)
最新推荐文章于 2019-11-30 00:46:01 发布