洛谷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/+

+++++++++++++++++++++++++++++++++++++++++++

posted @ 2018-05-26 21:34  luyouqi233  阅读(367)  评论(0编辑  收藏  举报