UESTC 1601 艾尔大停电2 二维树状数组+区间更新

129 篇文章 0 订阅
117 篇文章 2 订阅

艾尔大停电2

Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)


Submit  Status
(剧情提要:请看上题)


阿塔尼斯的新式矩形能量场成功的研制出来了。但是实验过程中却发现了一个巨大的问题,一股神秘的东方力量影响了新式能量场,两个能量场互相覆盖的区域将会互相抵消,变回无能量场区。


有趣的是,如果这个区域被第三个能量场覆盖,它将仍是有效的能量场区,当然如果有第四个能量场,那么就会和第三个能量场抵消,又变成无能量场区……也就是说,一个能量场将会把它范围内的能量场区变为非能量场区,把非能量场区变为能量场区。


现在,阿塔尼斯正在建造一些能量场,你需要知道某些时刻某个坐标点上是否是有效的能量场区。


Input

(注意能量场形式与上题的不同)


本题有多组数据。第一行一个正整数T(T<=10)表示数据的组数。


每组数据第一行一个正整数N(N<=50000),表示操作的次数。


接下来N行形容按时间顺序进行的N次操作,每行可能有两种形式:


1、一个大写字母C和四个正整数 C x1 y1 x2 y2 (1 <= x1 <= x2 <= 1000, 1 <= y1 <= y2 <= 1000) 表示以(x1,y1)为左下角(x2,y2)为右上角建造一个平行坐标轴的矩形能量场(包括边界)。


2、一个大写字母Q和两个正整数 Q x y (1 <= x, y <= 1000) 表示询问坐标(x,y)是否是有效的能量场区。


Output

对于每个询问输出一行一个整数。如果是有效的能量场区输出1,否则输出0。


Sample input and output

Sample Input Sample Output
1
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
1
0
0
1


Source

2017 UESTC Training for Data Structures

UESTC 1601 艾尔大停电2


My Solution

题意:每次对一个矩形更新操作,单点查询,求该点被更新的次数。


二维树状数组+区间更新
用二维树状数组, get(x, y)表示 1,1到x,y这个矩形的面积或者说矩阵的元素和,
所以对于读入的每个x1,y1,x2,y2。
可以在 (x1, y1)这里插入一个1,然后为了抵消影响在(x2+1, y2+1)插入一个 -1,
在(x2+1, y1)和(x1, y2+1)也插入一个-1,
这就是树状数组区间更新的常用做法,推广到二维也是一样。
这里如果查询x > x2+1, y > y2+1,的时候会有 k个1和3*k个-1,但并没有影响,
3*(-1) + 1 = -2也表示0,故没有影响。
查询的时候直接 get(x,y),然后while(ans < 0)则加一个偶数;从而变成非负整数,
输出ans%2即可
复杂度 O(n*n*logn*logn)


#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int MAXN = 1e3 + 8;

int Tree[MAXN][MAXN];
inline int lowbit(int x)
{
    return (x & -x);
}
inline int add(int x, int y, int value)
{
    int i, j;
    for (i = x; i < MAXN; i += lowbit(i)){
        for (j = y; j < MAXN; j += lowbit(j)){
            Tree[i][j] += value;
        }
    }
}
inline int get(int x, int y)
{
    int res = 0, i, j;
    for (i = x; i; i -= lowbit(i)){
        for (j = y; j; j -= lowbit(j)){
            res += Tree[i][j];
        }
    }
    return res;
}

//!@ProLights
/**
前面陈斐童在我电脑上交过题,后来去上课了。
刚刚写完不小心用他(没有 Logout)的号交了一发,
希望查重的时候看看我这里的注释,谢谢
**/

int main() {
    #ifdef LOCAL
    freopen("q.txt", "r", stdin);
    //freopen("q.out", "w", stdout);
    #endif // LOCAL
    //ios::sync_with_stdio(false); cin.tie(0);

    int T, n, i, x1, y1, x2, y2, ans;
    char op;
    scanf("%d", &T);
    while(T--){
        memset(Tree, 0, sizeof(Tree));
        scanf("%d", &n);
        while(n--){
            getchar(); getchar();
            op = getchar();
            //cin >> op;
            if(op == 'C'){
               scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
               add(x2+1, y2+1, -1);
               add(x2+1, y1, -1);
               add(x1, y2+1, -1);
               add(x1, y1, 1);

            }
            else{
                scanf("%d%d", &x1, &y1);
                ans = get(x1, y1);
                while(ans < 0) ans += (MAXN*MAXN);
                printf("%d\n", ans % 2);
            }
        }
    }
    return 0;
}


  Thank you!

                                                                                                                                             ------from ProLights

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值