1. 程式人生 > >HDU 1542——Atlantis(矩形面積並:線段樹+掃描線)

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]表示儲存區間被覆蓋長度。

更多細節詳見

程式碼:

#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)
{
    if(cnt[o<<1]==-1 || cnt[o<<1|1]==-1) cnt[o]=-1;      //左右節點區間有狀態不一致或者兩者狀態不一致則該節點區間cnt也為-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
*/