luogu P3801 红色的幻想乡 |容斥+树状数组

题目描述

经过上次失败后,蕾米莉亚决定再次发动红雾异变,但为了防止被灵梦退治,她决定将红雾以奇怪的阵势释放。

我们将幻想乡看做是一个 \(n \times m\)的方格地区,一开始没有任何一个地区被红雾遮盖。蕾米莉亚每次站在某一个地区上,向东南西北四个方向各发出一条无限长的红雾,可以影响到整行/整列,但不会影响到她所站的那个地区。如果两阵红雾碰撞,则会因为密度过大而沉降消失。灵梦察觉到了这次异变,决定去解决它。但在解决之前,灵梦想要了解一片范围红雾的密度。可以简述为两种操作:

1 x y 蕾米莉亚站在坐标 \((x,y)\) 的位置向四个方向释放无限长的红雾。

2 x1 y1 x2 y2 询问左上点为\((x1,y1)\),右下点为 \((x2,y2)\) 的矩形范围内,被红雾遮盖的地区的数量。

输入格式

第一行三个整数 \(n,m,q\),表示幻想乡大小为 \(n \times m\),有 \(q\) 个询问。

接下来 \(q\) 行,每行 \(3\) 个或 \(5\) 个整数,用空格隔开,含义见题目描述。

输出格式

对于每一个操作 \(2\),输出一行一个整数,表示对应询问的答案。

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+5;
#define int long long
int n,m,q,c[N][2];
inline void add(int x,int y,int op){
	for(;x<N;x+=x&(-x))c[x][op]+=y;
}
inline int sum(int x,int op){
	int ans=0;
	for(;x;x-=x&(-x))ans+=c[x][op];
	return ans;
}
signed main(){	
	cin>>n>>m>>q;
	int t,x,y,x1,x2,y1,y2;
	while(q--){
		scanf("%lld",&t);
		if(t==1){
			scanf("%lld%lld",&x,&y);
			if(sum(x,0)-sum(x-1,0))add(x,-1,0);
			else add(x,1,0);
			
			if(sum(y,1)-sum(y-1,1))add(y,-1,1);
			else add(y,1,1);
			
		}else{
			scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
			x=sum(x2,0)-sum(x1-1,0),y=sum(y2,1)-sum(y1-1,1);
			int ans=(y2-y1+1)*x+(x2-x1+1)*y-x*y*2;
			printf("%lld\n",ans);
		}
	}
} 
posted @ 2021-10-06 20:19  白木偶君  阅读(30)  评论(0编辑  收藏  举报