【POJ 1151】Atlantis

题目描述

n ( n 100 ) 个矩形的面积并。

吐槽

此题十分玄学,开始敲了一份代码,调了一晚上不过,返回 MLE

今天上午继续调试,发现网上的代码开 G++ 过不去,发现原来是卡 %lf,改成 %f 网上的代码就能过了,对拍了半天拍不出错,肉眼查出 query(int x) 那里应该是 query(double x),不然会 RE 做了很多简化之后在 入门OJ 上过了,但在 POJ 上 WA,去掉简化的内容就在 POJ 上过了,心累。

算法分析

离散化后使用扫描线,从左向右(也可以从上到下)扫描矩形与扫描线平行的边,用线段树维护目前的覆盖情况。

这个线段树不是普通的线段树,普通线段树貌似搞不了,我们发现,对于区间的增减总是成对出现,那么这里的线段树就是仅仅用来将线段拆分成 l o g 2 n 段以降低时间复杂度的,因此不必下传标记,只要记录当前段被覆盖的次数,维护当前区间内被覆盖的长度即可。

代码实现

#include <cstdio>
#include <algorithm>
const int maxn=105;
struct ask {
    double t,x,l,r;
    bool operator < (const ask &rhs) const {
        return x<rhs.x;
    }
} asks[2*maxn];
double hash[2*maxn];int idx=0;
inline int query(double x) {return std::lower_bound(hash,hash+idx,x)-hash;}
namespace SGT {
    int n,cnt[4*2*maxn];double ans[4*2*maxn];
    void build(int o,int l,int r) {
        if(l==r) ans[o]=cnt[o]=0;
        else {
            int mid=(l+r)>>1;
            build(o<<1,l,mid);build(o<<1|1,mid+1,r);
            ans[o]=cnt[o]=0;
        }
    }
    inline void init(int N) {n=N;build(1,1,n);}
    int ql,qr;
    void add(int o,int l,int r) {
        if(ql<=l&&r<=qr) {
            ++cnt[o];
            ans[o]=hash[r]-hash[l-1];
        }
        else {
            int mid=(l+r)>>1;
            if(ql<=mid) add(o<<1,l,mid);
            if(mid+1<=qr) add(o<<1|1,mid+1,r);
            if(!cnt[o]) ans[o]=ans[o<<1]+ans[o<<1|1];
        }
    }
    inline void add(int l,int r) {ql=l;qr=r;add(1,1,n);}
    void clear(int o,int l,int r) {
        if(ql<=l&&r<=qr) {
            --cnt[o];
            if(!cnt[o]) ans[o]=ans[o<<1]+ans[o<<1|1];
        }
        else {
            int mid=(l+r)>>1;
            if(ql<=mid) clear(o<<1,l,mid);
            if(mid+1<=qr) clear(o<<1|1,mid+1,r);
            if(!cnt[o]) ans[o]=ans[o<<1]+ans[o<<1|1];
        }
    }
    inline void clear(int l,int r) {ql=l;qr=r;clear(1,1,n);}
    inline double query() {return ans[1];}
}
int main() {
    int n,kase=0;
    while(scanf("%d",&n)==1&&n) {
        idx=0;double x1,y1,x2,y2;
        for(int i=0;i<n;++i) {
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            asks[i]=(ask){1,x1,y1,y2};asks[n+i]=(ask){-1,x2,y1,y2};
            hash[idx++]=y1;hash[idx++]=y2;
        }
        std::sort(hash,hash+idx);idx=std::unique(hash,hash+idx)-hash;
        std::sort(asks,asks+2*n);
        SGT::init(idx);
        double ans=0,last=0;
        for(int i=0;i<2*n;++i) {
            int l=query(asks[i].l)+1,r=query(asks[i].r);
            ans+=SGT::query()*(asks[i].x-last);
            if(asks[i].t==1) SGT::add(l,r);
            else if(asks[i].t==-1) SGT::clear(l,r);
            last=asks[i].x;
        }
        if(kase) printf("\n");
        printf("Test case #%d\nTotal explored area: %.2f\n",++kase,ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/WHZ2018/article/details/81329369