洛谷3801:红色的幻想乡——题解
https://www.luogu.org/problemnew/show/P3801
经过上次失败后,蕾米莉亚决定再次发动红雾异变,但为了防止被灵梦退治,她决定将红雾以奇怪的阵势释放。
我们将幻想乡看做是一个n*m的方格地区,一开始没有任何一个地区被红雾遮盖。蕾米莉亚每次站在某一个地区上,向东南西北四个方向各发出一条无限长的红雾,可以影响到整行/整列,但不会影响到她所站的那个地区。如果两阵红雾碰撞,则会因为密度过大而沉降消失。灵梦察觉到了这次异变,决定去解决它。但在解决之前,灵梦想要了解一片范围红雾的密度。可以简述为两种操作:
1 x y 蕾米莉亚站在坐标(x,y)的位置向四个方向释放无限长的红雾。
2 x1 y1 x2 y2 询问左上点为(x1,y1),右下点为(x2,y2)的矩形范围内,被红雾遮盖的地区的数量。
我们将1操作改一下,改为先在x行放雾,后在y列放雾。
没错,这两个操作在一起就是1操作。
维护两棵线段树,记录当前有哪些行/列被覆盖过,则答案就是(在区间范围内的)行数*(y2-y1+1)+列数*(x2-x1+1)-行数*列数*2(也就是把它们相交的点抠掉啦)
(这题再次体现我的智商问题。)
#include<iostream> #include<cstdio> #include<cmath> using namespace std; typedef long long ll; const int N=1e5+5; inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch=='-';ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } int tr[N*4][2],n,m,q; void mdy(int a,int l,int r,int k,int p){ if(l==r){ tr[a][p]^=1; return; } int mid=(l+r)>>1; if(k<=mid)mdy(a<<1,l,mid,k,p); else mdy(a<<1|1,mid+1,r,k,p); tr[a][p]=tr[a<<1][p]+tr[a<<1|1][p]; } int qry(int a,int l,int r,int l1,int r1,int p){ if(r1<l||r<l1)return 0; if(l1<=l&&r<=r1)return tr[a][p]; int mid=(l+r)>>1; return qry(a<<1,l,mid,l1,r1,p)+qry(a<<1|1,mid+1,r,l1,r1,p); } int main(){ n=read(),m=read(),q=read(); for(int i=1;i<=q;i++){ int op=read(); if(op==1){ int x=read(),y=read(); mdy(1,1,n,x,0);mdy(1,1,m,y,1); }else{ int x1=read(),y1=read(),x2=read(),y2=read(); int ans1=qry(1,1,n,x1,x2,0); int ans2=qry(1,1,m,y1,y2,1); printf("%lld\n",(ll)ans1*(y2-y1+1)+(ll)ans2*(x2-x1+1)-(ll)2*ans1*ans2); } } return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++