您的位置:首页 > 其它

poj 3067 Japan 二维树状数组(入门)

2013-07-28 22:03 405 查看
/**
*     二维树状数组(入门):
*     二维树状数组直接上就行了。。。
*     用结构体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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: