HDU 1542——Atlantis(矩形面积并:线段树+扫描线)

Atlantis

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 19526    Accepted Submission(s): 7850

Problem Description

There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of the island. But unfortunately, these maps describe different regions of Atlantis. Your friend Bill has to know the total area for which maps exist. You (unwisely) volunteered to write a program that calculates this quantity.

Input

The input file consists of several test cases. Each test case starts with a line containing a single integer n (1<=n<=100) of available maps. The n following lines describe one map each. Each of these lines contains four numbers x1;y1;x2;y2 (0<=x1<x2<=100000;0<=y1<y2<=100000), not necessarily integers. The values (x1; y1) and (x2;y2) are the coordinates of the top-left resp. bottom-right corner of the mapped area.

The input file is terminated by a line containing a single 0. Don’t process it.

Output

For each test case, your program should output one section. The first line of each section must be “Test case #k”, where k is the number of the test case (starting with 1). The second one must be “Total explored area: a”, where a is the total explored area (i.e. the area of the union of all rectangles in this test case), printed exact to two digits to the right of the decimal point.

Output a blank line after each test case.

Sample Input

2 10 10 20 20 15 15 25 25.5 0

Sample Output

Test case #1 Total explored area: 180.00

题意:给出n个矩形的左下坐标和右上坐标,求所有矩形的面积并。

思路:

1. 将所有矩形的上下边存结构体,储存其x1,x2,y和一个下底标记(1),上底标记(-1),并将y从小到大排序(计算面积用)

2. 因为x范围较大而n较小,所以考虑将所有x离散化后在进行线段树上的区间操作

如样例(图画的有点丑qwq),将 10 15 20 25离散为1 2 3 4四个不同的坐标,然后就有1 2 3个区间要维护,分别是1-2(10-15),2-3(15-20),3-4(20-25),这样计算面积时分别计算的是三个不同颜色内的面积(从下往上)高可以根据前一条边的y减去当前边的y所得到,宽则需要维护两个线段树,cnt[i]记录cnt[i]表示区间是否被覆盖,为-1时表示其左右区间状态不一致,需要下推,len[i]表示储存区间被覆盖长度,那么每次都可以得到一个有效长度len[1]即为宽。

1:w 10     h 5

2:w 15     h 5

3:w 10     h 5.5

有关更详细讲解: https://blog.csdn.net/lwt36/article/details/48908031 此篇少了push_down的操作

 更多细节详见

代码:

#include<bits/stdc++.h>
#define lson l,mid,o<<1
#define rson mid+1,r,o<<1|1
#define N 205
using namespace std;

int cnt[N<<2];    //记录cnt[i]表示区间是否被覆盖 为-1时表示其左右区间状态不一致,需要下推
double len[N<<2]; //储存区间被覆盖长度 注意数据类型

double X[N<<1];
struct edge
{
    double l,r,h;
    int f;
    edge(){}
    edge(double l,double r,double h,int f):l(l),r(r),h(h),f(f){}
    bool operator < (const edge &b) const
    {
        return h<b.h;
    }
}e[N<<1];

void push_up(int o)
{
    //左右节点区间有状态不一致或者两者状态不一致则该节点区间cnt也为-1
    if(cnt[o<<1]==-1 || cnt[o<<1|1]==-1) cnt[o]=-1;      
    else if(cnt[o<<1]!=cnt[o<<1|1])      cnt[o]=-1;
    else                                 cnt[o]=cnt[o<<1];

    len[o]=len[o<<1]+len[o<<1|1];
}

void push_down(int o,int l,int r)
{
    if(cnt[o]!=-1)  //当状态一致时才下推
    {
        int mid=l+r>>1;
        cnt[o<<1]=cnt[o<<1|1]=cnt[o];
        len[o<<1]=(cnt[o] ? X[mid+1]-X[l] :0);
        len[o<<1|1]=(cnt[o] ? X[r+1]-X[mid+1] :0);
    }
}

void build(int l,int r,int o)
{
    if(l==r)
    {
        cnt[o]=0;
        len[o]=0.0;
        return;
    }
    int mid=l+r>>1;
    build(lson);
    build(rson);
    push_up(o);
}

void update(int L,int R,int v,int l,int r,int o)
{
    if(L<=l&&r<=R)
    {
        if(cnt[o]!=-1)
        {
            cnt[o]+=v;
            len[o]=(cnt[o] ? X[r+1]-X[l]:0);
            return;
        }
    }
    push_down(o,l,r);
    int mid=l+r>>1;
    if(L<=mid) update(L,R,v,lson);
    if(R>mid)  update(L,R,v,rson);
    push_up(o);
}


int main()
{
    int n,ca=1;
    while(scanf("%d",&n),n)
    {
        double x1,y1,x2,y2;
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            X[i]=x1,X[i+n]=x2;
            e[i]=edge(x1,x2,y1,1);
            e[i+n]=edge(x1,x2,y2,-1);
        }
        sort(e+1,e+1+2*n);
        int m=unique(X+1,X+1+2*n)-X-1;
        sort(X+1,X+1+m);
        build(1,m-1,1);         //m个不同的点分成m-1个区间

        double ans=0.0;
        for(int i=1;i<=2*n-1;i++)
        {
            int l=lower_bound(X+1,X+1+m,e[i].l)-X;
            int r=lower_bound(X+1,X+1+m,e[i].r)-X-1;
            //printf("%d %d\n",l,r);
            update(l,r,e[i].f,1,m-1,1);
            //printf("%f  %f\n",len[1],e[i+1].h-e[i].h);
            ans+=len[1]*(e[i+1].h-e[i].h);
        }
        printf("Test case #%d\n",ca++);
        printf("Total explored area: %.2lf\n",ans);
        puts("");
    }
    return 0;
}
/*
    3
    0 0 10 10
    20 20 50 50
    10 10 100 100

8200
*/

猜你喜欢

转载自blog.csdn.net/QuincyTan/article/details/83719928
今日推荐