题意
给定一个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;
}