[Ahoi2008]Rectangle 解题报告

来源:互联网 发布:一个域名绑定多个ip 编辑:程序博客网 时间:2024/05/29 13:11

又是喜闻乐见的只会傻逼做法的题。。跟我跑得差不多快的人都写了1K,我写了快4K。。
并不知道他们怎么搞的,说下我的做法:
考虑按x从大到小的扫描线,每次在矩形的左下角(x1,y1)插入一个数y2,判断一个矩形(x1,y1)(x2,y2)是否被包含就相当于询问矩形(0,0)(x1,y1)的最大值是否大于y2。就是要支持单点插入,矩形最大值。一个显然比较乱搞的做法就是K-D树。
在k-d树上查询的时候因为是dfs,所以可以各种剪枝。建树的时候可以类似划分树一样建,就是O(nlogn)的。。我一开始建的特别暴力,O(nlog2n)建树,也没剪枝,T的飞起。。

最后口胡一下科学的做法该怎么搞(其实我感觉kd树就挺科学的。。)。如果我们对扫描线用cdq分治的话,就相当于是有一坨点,然后查询前缀矩形max,这个就可以用扫描线+bit搞出来。时间复杂度就是O(nlog2n)

我看别人都写得特别短。。听说是暴力乱搞。。不知道他们怎么搞的。。
代码:

#include<cstdio>#include<iostream>using namespace std;#include<algorithm>#include<cstdlib>#include<cstring>#include<cmath>const int N=2e5+5;struct KS{    int lx,rx,ly,ry,max;}kdtree[N<<2];struct PS{    int x,y;}point[N];int a[N],b[N],tmp[N];int pos[N];bool cmp1(const int &a,const int &b){    return point[a].x<point[b].x;}bool cmp2(const int &a,const int &b){    return point[a].y<point[b].y;}const int inf=0x7fffffff;void build(int node,int depth,int tot){    //printf("---%d,%d---\n",node,tot);    kdtree[node]=(KS){point[a[0]].x,point[a[tot-1]].x,point[b[0]].y,point[b[tot-1]].y,-1};    if(tot==1){        //printf("%d:%d\n",node,a[0].i);        pos[a[0]]=node;    }    else{        /*printf("a=");        for(int i=0;i<tot;++i)printf("%d(%d) ",a[i].i,a[i].x);        puts("");        printf("b=");        for(int i=0;i<tot;++i)printf("%d ",b[i].i);        puts("");*/        //if(rand()&1){        if(depth){            //puts("x!");            int ttot=0;            for(int i=0;i<tot;++i)                if(point[b[i]].x<point[a[tot>>1]].x){                    tmp[ttot++]=b[i];                    //printf("Get:%d %d %d\n",b[i].i,b[i].x,a[tot>>1].x);                }            for(int i=0;i<tot;++i)                if(point[b[i]].x>=point[a[tot>>1]].x)                    tmp[ttot++]=b[i];            memcpy(b,tmp,sizeof(int)*tot);        }        else{            //puts("y!");            int ttot=0;            for(int i=0;i<tot;++i)                if(point[a[i]].y<point[b[tot>>1]].y)                    tmp[ttot++]=a[i];            for(int i=0;i<tot;++i)                if(point[a[i]].y>=point[b[tot>>1]].y)                    tmp[ttot++]=a[i];            memcpy(a,tmp,sizeof(int)*tot);        }        /*printf("a=");        for(int i=0;i<tot>>1;++i)printf("%d ",a[i].i);        puts("");        printf("b=");        for(int i=0;i<tot>>1;++i)printf("%d ",b[i].i);        puts("");*/        build(node<<1,depth^1,tot>>1);        memcpy(a,a+(tot>>1),sizeof(int)*(tot-(tot>>1)));        memcpy(b,b+(tot>>1),sizeof(int)*(tot-(tot>>1)));        build(node<<1|1,depth^1,tot-(tot>>1));    }}void update(int node,int A){    //cout<<"update("<<node<<','<<A<<")\n";    for(;node;node>>=1)kdtree[node].max=max(kdtree[node].max,A);}bool query(int node,int rx,int ry,int downlimit){    //printf("%d={lx=%d,rx=%d,ly=%d,ry=%d,max=%d} (%d,%d)\n",node,kdtree[node].lx,kdtree[node].rx,kdtree[node].ly,kdtree[node].ry,kdtree[node].max,rx,ry);    if(kdtree[node].max<downlimit)return 0;    if(kdtree[node].rx<=rx&&kdtree[node].ry<=ry)return kdtree[node].max>downlimit;    else{        if(kdtree[node].lx<=rx&&kdtree[node].ly<=ry){            if(query(node<<1,rx,ry,downlimit))return 1;            if(query(node<<1|1,rx,ry,downlimit))return 1;        }        return 0;    }}struct RS{    int x1,y1;    int x2,y2;    int i;    bool operator < (const RS & o)const{        return x2<o.x2;    }}rec[N];char * cp=(char *)malloc(10000000);void in(int &x){    while(*cp<'0'||*cp>'9')++cp;    for(x=0;*cp>='0'&&*cp<='9';)x=x*10+(*cp++^'0');}int main(){    freopen("bzoj_1790.in","r",stdin);    fread(cp,1,10000000,stdin);    int n;    in(n);    for(int i=n;i--;){        in(rec[i].x1),in(rec[i].y1);        in(rec[i].x2),in(rec[i].y2);        rec[i].i=i;        point[i]=(PS){rec[i].x1,rec[i].y1};        b[i]=a[i]=i;    }    sort(a,a+n,cmp1);    sort(b,b+n,cmp2);    build(1,0,n);    //for(int i=n;i--;)printf("pos(%d)=%d\n",i,pos[i]);    sort(rec,rec+n);    int ans=0;    for(int i=n;i--;){        //printf("(%d,%d)-(%d,%d) i=%d\n",rec[i].x1,rec[i].y1,rec[i].x2,rec[i].y2,rec[i].i);        ans+=query(1,rec[i].x1-1,rec[i].y1-1,rec[i].y2);        update(pos[rec[i].i],rec[i].y2);    }    printf("%d\n",ans);}

总结:
①矩阵/高维问题可以用cdq分治搞一维,这样时间/空间都会比较好。
②k-d树建树的时候可以像划分树一样建,这样就是O(nlogn);查询的时候多搞点剪枝,就会跑得比较快了。

0 0