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

题目描述

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

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

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

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

输入格式

第一行三个整数 (n,m,q),表示幻想乡大小为 (n imes 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
",ans);
		}
	}
} 
不以物喜,不以己悲
原文地址:https://www.cnblogs.com/naruto-mzx/p/15374080.html