【题目】
题目背景:
蕾米莉亚的红雾异变失败后,很不甘心。
题目描述:
经过上次失败后,蕾米莉亚决定再次发动红雾异变,但为了防止被灵梦退治,她决定将红雾以奇怪的阵势释放。
我们将幻想乡看做是一个 n × m n\times m n×m 的方格地区,一开始没有任何一个地区被红雾遮盖。蕾米莉亚每次站在某一个地区上,向东南西北四个方向各发出一条无限长的红雾,可以影响到整行和整列,但不会影响到她所站的那个地区。如果两阵红雾碰撞,则会因为密度过大而沉降消失。灵梦察觉到了这次异变,决定去解决它。但在解决之前,灵梦想要了解一片范围红雾的密度。可以简述为两种操作:
1 1 1 x x x y y y:蕾米莉亚站在坐标 ( x , y ) (x,y) (x,y) 的位置向四个方向释放无限长的红雾。
2 2 2 x 1 x_1 x1 y 1 y_1 y1 x 2 x_2 x2 y 2 y_2 y2 询问左上点为 ( x 1 , y 1 ) (x_1,y_1) (x1,y1),右下点为 ( x 2 , y 2 ) (x_2,y_2) (x2,y2) 的矩形范围内,被红雾遮盖的地区的数量。
输入格式:
第一行三个整数 n , m , q n,m,q n,m,q,表示幻想乡大小为 n × m n\times m n×m,有 q q q 个询问。
接下来 q q q 行,每行 3 3 3 个或 5 5 5 个整数,用空格隔开,含义见题目描述。
输出格式:
对于每一个操作 2 2 2,输出一行一个整数,表示对应询问的答案。
样例数据:
输入
4 4 3
1 2 2
1 4 4
2 1 1 4 4
输出
8
样例解释:
用 o 表示没有红雾,x 表示有红雾,两次释放红雾后幻想乡地图如下:
oxox
xoxo
oxox
xoxo
数据范围:
对于 20 % 20\% 20% 的数据, 1 ≤ n , m , q ≤ 200 1\le n,m,q\le200 1≤n,m,q≤200
对于 40 % 40\% 40% 的数据, 1 ≤ n , m , q ≤ 1000 1\le n,m,q\le1000 1≤n,m,q≤1000
对于 100 % 100\% 100% 的数据, 1 ≤ n , m , q ≤ 100000 1\le n,m,q\le100000 1≤n,m,q≤100000
1 ≤ x 1 , x 2 , x ≤ n 1\le x_1,x_2,x\le n 1≤x1,x2,x≤n, x 1 ≤ x 2 x_1\le x_2 x1≤x2
1 ≤ y 1 , y 2 , y ≤ m 1\le y_1,y_2,y\le m 1≤y1,y2,y≤m, y 1 ≤ y 2 y_1\le y_2 y1≤y2
【分析】
一开始看到这道题,想到用二维树状数组(二维线段树)来做,但看到数据范围。。。
然后脑补了一些鬼畜的想法,最后发现自己想复杂了
我们对于行和列都分别建一颗线段树,分别维护这一行(或这一列)有没有红雾
用 1 1 1 表示有红雾,用 0 0 0 表示没有红雾的话
对于每个点,如果只有行是 1 1 1 或者只有列是 1 1 1,那么这个点就有红雾(可以画个图理解一下)
那么修改就好办了,直接对行和列异或 1 1 1 就行了
那么询问怎么搞呢?
把 [ x 1 x_1 x1 , x 2 x_2 x2 ] 中 1 1 1 的数量记为 n u m x , 1 num_{x,1} numx,1, 0 0 0 的数量记为 n u m x , 0 num_{x,0} numx,0,对于 y y y 同理
显然的,由于要找 ( x 1 , y 1 ) (x_1,y_1) (x1,y1) 到 ( x 2 , y 2 ) (x_2,y_2) (x2,y2) 的有红雾的点的个数,那就是 n u m x , 1 × n u m y , 0 + n u m x , 0 × n u m y , 1 num_{x,1}\times num_{y,0}+num_{x,0}\times num_{y,1} numx,1×numy,0+numx,0×numy,1
那么用线段树乱搞一下就可以了
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
using namespace std;
int sum[2][N<<2];
void modify(int root,int l,int r,int x,int k)
{
if(l==r)
{
sum[k][root]^=1;
return;
}
int mid=(l+r)>>1;
if(x<=mid) modify(root<<1,l,mid,x,k);
else modify(root<<1|1,mid+1,r,x,k);
sum[k][root]=sum[k][root<<1]+sum[k][root<<1|1];
}
int query(int root,int l,int r,int x,int y,int k)
{
if(l>=x&&r<=y)
return sum[k][root];
int ans=0,mid=(l+r)>>1;
if(x<=mid) ans+=query(root<<1,l,mid,x,y,k);
if(y>mid) ans+=query(root<<1|1,mid+1,r,x,y,k);
return ans;
}
int main()
{
int n,m,q,i,s,x,y,x1,y1;
scanf("%d%d%d",&n,&m,&q);
for(i=1;i<=q;++i)
{
scanf("%d%d%d",&s,&x,&y);
if(s==1) modify(1,1,n,x,0),modify(1,1,m,y,1);
else
{
scanf("%d%d",&x1,&y1);
long long temp1=query(1,1,n,x,x1,0);
long long temp2=query(1,1,m,y,y1,1);
long long ans=temp1*(y1-y+1-temp2)+temp2*(x1-x+1-temp1);
printf("%lld\n",ans);
}
}
return 0;
}