[Ahoi2008]Rectangle 解题报告

11 篇文章 0 订阅
4 篇文章 0 订阅

又是喜闻乐见的只会傻逼做法的题。。跟我跑得差不多快的人都写了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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值