首页 > 代码库 > 红色的幻想乡

红色的幻想乡

题目背景

蕾米莉亚的红雾异变失败后,很不甘心。

题目描述

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

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

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

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

输入输出格式

输入格式:

 

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

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

 

输出格式:

 

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

 

输入输出样例

输入样例#1:
4 4 3
1 2 2
1 4 4
2 1 1 4 4
输出样例#1:
8

说明

样例解释:

用o表示没有红雾,x表示有红雾,两次释放红雾后幻想乡地图如下:

oxox

xoxo

oxox

xoxo

数据范围:

对于20%的数据,1<=n,m,q<=200

对于 40%的数据,1<=n,m,q<=1000

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

1<=x1,x2,x<=n x1<=x2

1<=y1,y2,y<=m y1<=y2

by-orangebird

 线段树的运用。

用两个线段树表示行和列,维护第x行,第y列有没有放过雾

由于两片红雾会抵消,相当于每次修改,对应行^=1,对应列^=1。

每一次询问,即区间求和。令x=∑c1[x2-x1],y=∑c2[y2-y1];

由容斥原理,可知ans=x*(y2-y1+1)+y*(x2-x1+1)-x*y*2;

记得开long long

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int c1[400001],c2[400001],n,m,q;
void addh(int rt,int l,int r,int x)
{
	if (l==r)
	{
		c1[rt]^=1;
		return;
	}
	int mid=(l+r)/2;
	if (x<=mid) addh(rt*2,l,mid,x);
	else addh(rt*2+1,mid+1,r,x);
 c1[rt]=c1[rt*2]+c1[rt*2+1];
}
void addl(int rt,int l,int r,int x)
{
	if (l==r)
	{
		c2[rt]^=1;
		return;
	}
	int mid=(l+r)/2;
	if (x<=mid) addl(rt*2,l,mid,x);
	else addl(rt*2+1,mid+1,r,x);
 c2[rt]=c2[rt*2]+c2[rt*2+1];
}
int geth(int rt,int l,int r,int L,int R)
{
	if (l>=L&&r<=R)
	{
		return c1[rt];
	}
	 int mid=(l+r)/2; 
	int s=0;
	 if (L<=mid) s+=geth(rt*2,l,mid,L,R);
	 if (R>mid) s+=geth(rt*2+1,mid+1,r,L,R);
	return s;
}
int getl(int rt,int l,int r,int L,int R)
{
	if (l>=L&&r<=R)
	{
		return c2[rt];
	}
	 int mid=(l+r)/2; 
	int s=0;
	 if (L<=mid) s+=getl(rt*2,l,mid,L,R);
	 if (R>mid) s+=getl(rt*2+1,mid+1,r,L,R);
	return s;
}
int main()
{int i,j,ch,x,y,x1,x2,y1,y2;
   scanf("%d%d%d",&n,&m,&q);
    for (i=1;i<=q;i++)
    {
    	scanf("%d",&ch);
    	if (ch==1)
    	{
    		scanf("%d%d",&x,&y);
    		addh(1,1,n,x);
    		addl(1,1,n,y);
    	}
    	if (ch==2)
    	{
    		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
                int x=geth(1,1,n,x1,x2);
		   int y=getl(1,1,n,y1,y2);
		   printf("%lld\n",y*(long long)(x2-x1+1)+x*(long long)(y2-y1+1)-(long long)x*y*2);		
    	}
    }
}

  

红色的幻想乡