[JZOJ3893] 画矩形

来源:互联网 发布:n卡优化守望先锋 编辑:程序博客网 时间:2024/05/16 07:04

Description

有N个操作。

  • 在平面直角坐标系中画一个边与坐标轴平行的矩形,输入左下角点坐标和右上角点坐标。
  • 给出一个点坐标,查询被多少矩形覆盖。

所有点均在第一象限或X,Y轴的非负半轴上,N<=200000

Solution

经典的CDQ分治(整体二分)。
设矩形(x,y)(p,q)
一个矩形可以拆成四个点,(x,y),(x,q+1),(p+1,y),(p+1,q+1)
第一个点和第四个点权值为1,另两个为-1。
那么对于查询就是统计原点与这个点构成的矩形中的所有点权和(思考为什么?)

拆点以后,根据读入时间存起来。
显然只有左边的点对右边才有影响
二分X坐标,扫一遍对于[L,mid]的操作点就将它Y坐标打进树状数组,对于[mid,R]的查询点就用它的Y坐标在树状数组上查询

这样我们相当于将当前所有点分成了两部分,两个数组存起来分治下去,在mid上的点不用存。

因为坐标从0开始,可以先全部+1方便树状数组统计。
复杂度O(NlogN)

Code

#include <cstdio>#include <cmath>#include <algorithm>#include <cstdlib>#include <iostream>#include <cstring>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fod(i,a,b) for(int i=a;i>=b;i--)#define N 600015using namespace std;int a[2*N][4],n,q,c[N],lim,ans[N],b[20][N][4],n1,le[20];int lowbit(int k) {    return k&(-k);}void put(int k,int v){    while(k<=lim) c[k]+=v,k+=lowbit(k);}int get(int k){    int s=0;    while(k>0) s+=c[k],k-=lowbit(k);    return s;}void turn(int p,int q,int w){    le[p]++;    fo(i,0,3) b[p][le[p]][i]=b[q][w][i];}void doit(int l,int r,int p){     int mid=(l+r)/2;    if(l>r) return;    fo(i,1,le[p])    {        if(b[p][i][2]!=0&&b[p][i][0]<=mid) put(b[p][i][1],b[p][i][2]);        if(b[p][i][2]==0&&b[p][i][0]>=mid) ans[b[p][i][3]]+=get(b[p][i][1]);    }    fo(i,1,le[p]) if(b[p][i][2]!=0&&b[p][i][0]<=mid) put(b[p][i][1],-b[p][i][2]);    if(l<mid)    {        n1++,le[n1]=0;        fo(i,1,le[p]) if(b[p][i][0]<mid) turn(n1,p,i);         doit(l,mid-1,n1);        n1--;    }    if(mid<r)    {        n1++,le[n1]=0;        fo(i,1,le[p]) if(b[p][i][0]>mid) turn(n1,p,i);        doit(mid+1,r,n1);        n1--;    }}void nwp(int x,int y,int z,int t){    b[1][++le[1]][0]=x;    b[1][le[1]][1]=y;    b[1][le[1]][2]=z;    b[1][le[1]][3]=t;}int main(){    cin>>n;    q=0;    n1=1;    fo(i,1,n)    {        int p,x,y,l=0,r;        scanf("%d",&p);        if(p==0)         {            scanf("%d%d%d%d",&x,&y,&l,&r);            x++,y++,l++,r++;            nwp(x,y,1,i);            nwp(l+1,y,-1,i);            nwp(x,r+1,-1,i);            nwp(l+1,r+1,1,i);        }        else scanf("%d%d",&x,&y),nwp(++x,++y,0,i);        lim=max(lim,max(x,l+1));    }    doit(1,lim,1);    fo(i,1,le[1])    {        if(b[1][i][2]==0) printf("%d\n",ans[b[1][i][3]]);    }}
0 0
原创粉丝点击