POJ1151-Atlantis

chunlvxiong的博客


题目描述:

  有n个矩形(1≤n≤100),它们之间可能会重叠,输出其总面积。

思考&分析:

  很容易想到先把所有矩形的x,y坐标离散化,然后你可以对于每个矩形O(N^2)暴力覆盖,最后O(N^2)统计即可,时间复杂度O(N^3),可以A掉此题,但是我们有优秀地多的做法。

  你可以考虑先将矩形按照x坐标排序,然后按照x坐标从小到大扫过去,如果遇到的x坐标是一个矩形的开头,那么暴力O(N)覆盖其y坐标的范围,如果遇到的x坐标是一个矩形的结尾,也同样取消覆盖其y坐标的范围,对于每个x,O(N)扫统计出其y坐标上的总长度(可能由好几段组成),然后*对应x坐标的长度即可,时间复杂度O(N^2)。

  

  看看这幅图,你每次统计的部分就是涂上斜线的部分。

  然后这个O(N^2)是可以优化成O(NlogN)的-->相信大家都已经猜到用线段树优化了。

  顺带一提,虽然是区间修改,但是这个线段树并不用lazy标记,原因很简单,标记和删除的空间总是对应相同的。

贴代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=205;
int cnt_x,cnt_y,all_x,all_y;
double hash_x[maxn],hash_y[maxn];
double a1[maxn],b1[maxn],a2[maxn],b2[maxn];
int n;
struct seg{
    double sum;
    int cover;
}tree[maxn*4];
struct point{
    int x,y;
};
struct ju{
    point a,b;
}P[maxn],p[maxn];
bool cmp(double a,double b){
    return a<b;
}
void LSH(){
    sort(hash_x+1,hash_x+cnt_x+1,cmp);
    sort(hash_y+1,hash_y+cnt_y+1,cmp);
    all_x=1;
    for (int i=2;i<=cnt_x;i++)
    if (fabs(hash_x[i]-hash_x[i-1])>1e-8)
        hash_x[++all_x]=hash_x[i];
    all_y=1;
    for (int i=2;i<=cnt_y;i++)
    if (fabs(hash_y[i]-hash_y[i-1])>1e-8)
        hash_y[++all_y]=hash_y[i];
}
int find_x(double x){
    int L=1,R=all_x,mid=(L+R)>>1;
    while (fabs(hash_x[mid]-x)>1e-8){
        if (hash_x[mid]<x) L=mid+1;
        else R=mid-1;
        mid=(L+R)>>1;
    }
    return mid;
}
int find_y(double y){
    int L=1,R=all_y,mid=(L+R)>>1;
    while (fabs(hash_y[mid]-y)>1e-8){
        if (hash_y[mid]<y) L=mid+1;
        else R=mid-1;
        mid=(L+R)>>1;
    }
    return mid;
}
bool cmp1(ju a,ju b){
    return a.a.x<b.a.x;
}
bool cmp2(ju a,ju b){
    return a.b.x<b.b.x;
}
void build(int rt,int L,int R){
    tree[rt].sum=tree[rt].cover=0;
    if (L==R) return;
    int mid=(L+R)>>1;
    build(rt<<1,L,mid);
    build((rt<<1)|1,mid+1,R);
}
void pushup(int rt,int L,int R){
    if (tree[rt].cover)
        tree[rt].sum=hash_y[R+1]-hash_y[L];
    else
        if  (L==R) tree[rt].sum=0;
    else
        tree[rt].sum=tree[rt<<1].sum+tree[(rt<<1)|1].sum;
}
void change(int rt,int L,int R,int CL,int CR,int v){
    if (CL>R || CR<L) return;
    if (CL<=L && CR>=R){
        tree[rt].cover+=v;
        pushup(rt,L,R);
        return;
    }
    int mid=(L+R)>>1;
    change(rt<<1,L,mid,CL,CR,v);
    change((rt<<1)+1,mid+1,R,CL,CR,v);
    pushup(rt,L,R);
}
int main(){
    int Case=0;
    while (~scanf("%d",&n)){
        if (!n) break;
        cnt_x=cnt_y=0;
        for (int i=1;i<=n;i++){
            scanf("%lf%lf%lf%lf",&a1[i],&a2[i],&b1[i],&b2[i]);
            hash_x[++cnt_x]=a1[i],hash_x[++cnt_x]=b1[i];
            hash_y[++cnt_y]=a2[i],hash_y[++cnt_y]=b2[i];
        }
        LSH();
        for (int i=1;i<=n;i++){
            P[i].a.x=find_x(a1[i]),P[i].a.y=find_y(a2[i]);
            P[i].b.x=find_x(b1[i]),P[i].b.y=find_y(b2[i]);
            p[i]=P[i];
        }
        sort(P+1,P+n+1,cmp1);
        sort(p+1,p+n+1,cmp2);
        build(1,1,all_y-1);
        double ans=0;
        for (int X=1,i=1,j=1;X<all_x;X++){
            while (i<=n && P[i].a.x==X){
                change(1,1,all_y-1,P[i].a.y,P[i].b.y-1,1);
                i++;
            }
            while (j<=n && p[j].b.x==X){
                change(1,1,all_y-1,p[j].a.y,p[j].b.y-1,-1);
                j++;
            }
            ans+=(hash_x[X+1]-hash_x[X])*tree[1].sum;
        }
        printf("Test case #%d\n",++Case);
        printf("Total explored area: %.2lf\n",ans);
        puts("");
    }
    return 0;
}

 

posted @ 2017-08-16 19:54  chunlvxiong  阅读(386)  评论(0编辑  收藏  举报