数据结构小题

题意

给定一个n*m的方格地区,有以下两种操作。
1 x y 从坐标(x,y)的位置向四个方向释放无限长的红雾。
2 x1 y1 x2 y2 询问左上点为(x1,y1),右下点为(x2,y2)的矩形范围内,被红雾遮盖的地区的数量。
注意:释放红雾时脚下没有。
   两块红雾会抵消

对于100%的数据,1<=n,m,q<=100000


解析

我们可以在横轴和纵轴上分别建立树状数组,(加一,加第二次的话就减一)。统计答案的时候,看区间有多少横轴,多少纵轴,答案为纵轴数乘横方向长度+横轴数乘纵方向长度-横轴数乘纵轴数乘2。为什么乘2呢。首先横纵轴的交点是重复计算了的,要减一次。其次,根据题目意思,我们可以发现只要是横纵轴交点肯定是没有红雾的。所以还要减去一次。


#include <cstdio>
#include <algorithm>

#define Rep( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i<=(i##_END);i++)
#define For( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i!=(i##_END);i++)
#define Lop( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i>=(i##_END);i--)
#define Dnt( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i!=(i##_END);i--)

using std :: max;
using std :: min;

typedef long long LL;

const int maxx = 100000 + 25;

int n,m,x,y,z,t,f;
int x1,y1,x2,y2;
LL  tmp1,tmp2,CH3,CH2,OH;

int a[maxx],b[maxx];
LL T1[maxx],T2[maxx];

namespace Bit{

    void Add(LL *A,int x,int k,int s){
        for(int i=x;i<=s;i+=i&(-i))
            A[i] += k;
    }

    LL Query(LL *A,int x){
        LL ans = 0;
        for(int i=x;i;i-=i&(-i))
            ans += A[i];
        return ans;
    }

}

using namespace Bit;

int main(){
    scanf("%d%d%d",&n,&m,&t);
    while( t-- ){
        scanf("%d",&f);
        if(f == 1){
            scanf("%d%d",&x,&y);
            Add(T1,x,a[x]? -1 : 1,n);
            Add(T2,y,b[y]? -1 : 1,m);
            a[x] ^= 1;b[y] ^= 1;
        }
        if(f == 2){
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            tmp1 = Query(T1,x2) - Query(T1,x1-1);
            tmp2 = Query(T2,y2) - Query(T2,y1-1);
            CH3 = tmp1*(LL)(y2-y1+1);
            CH2 = -tmp2*(LL)(x2-x1+1);
            OH = 2*tmp1*tmp2;
            printf("%lld\n",CH3-CH2-OH);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值