POJ - 1151 Atlantis(線段樹維護掃描線+離散處理)

題目鏈接https://vjudge.net/contest/368031#problem/F
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 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表示有n個矩形,每一行兩個座標,x1,y1,x2,y2,分別表示左下角和右上角的座標。以此來表示矩形。
求最後所有矩形的面積。(重疊的部分只計算一次)

1. 引入掃描線

在這裏插入圖片描述

輸入的是兩個座標來表示矩形,對於每一個矩形引入兩條線,每一條線的相關變量:

struct line
{
    double x1,x2,y;
    int flag;
} p[N];

記錄矩形平行於x軸的的邊的各種信息。左右端點的座標,所對應的y軸的座標和是矩陣的上邊還是下邊。

2.離散化所有的橫座標(方便計算)

x[k++]=x1;
x[k++]=x2;
sort(x,x+k);
int length=unique(x,x+k)-x;///離散化處理:去重

3. 如何計算面積?

在這裏插入圖片描述
把每一條線按縱座標從小到大排序

看該線段所在區間上的cover是否爲0,若不爲0,就可以將並面積值加上(目前線段的y定位 - 上一線段的y定位)*(該區間的大小)。
線段樹維護的區間的有效長度。

在這裏插入圖片描述

第一次:
l=10,r=20,h=10,對應的區間爲(0,1)。
此時長度爲10,計算圖中黃色部分面積。

第二次:
l=15,r=25,h=15,對應的區間爲(1,2)。
此時長度爲15,計算圖中藍色部分面積。

第三次:
l=10,r=20,h=20,對應的區間爲(0,1)。
此時長度爲10(10~15被+1,-1抵消,cover=0不計算),計算圖中棕色部分面積。

代碼

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=4*1e4+10;
struct line
{
    double x1,x2,y;
    int flag;
} p[N];
struct Tree
{
    int l,r;
    int cover;
    double sum;
} tree[N];
double x[N];
int cmp(line t1,line t2)
{
    return t1.y<t2.y;
}
void build(int l,int r,int o)///初始化爲區間的初始化,不是點的初始化
{
    tree[o].l=l;
    tree[o].r=r;
    tree[o].cover=tree[o].sum=0;
    if(l==r)
        return;
    int mid=(l+r)>>1;
    build(l,mid,o<<1);
    build(mid+1,r,o<<1|1);
    return;
}
void pushdown(int o)
{
    if(tree[o].cover!=0)
        tree[o].sum=x[tree[o].r+1]-x[tree[o].l];
    else if(tree[o].l==tree[o].r)
        tree[o].sum=0;///若l,r表示點,此時l=r不表示區間,這裏的l,r爲區間,相同的思想
    else
        tree[o].sum=tree[o<<1].sum+tree[o<<1|1].sum;
    return;
}
void update(int l,int r,int kk,int o)
{
    if(l<=tree[o].l&&r>=tree[o].r)
    {
        tree[o].cover+=kk;
        pushdown(o);
        return;
    }
    int mid=(tree[o].l+tree[o].r)>>1;
    if(l<=mid)
        update(l,r,kk,o<<1);
    if(r>mid)
        update(l,r,kk,o<<1|1);
    pushdown(o);
    return;
}
int main()
{
    int n,t=1;
    while(~scanf("%d",&n)&&n)
    {
        int k=0;
        while(n--)
        {
            double x1,x2,y1,y2;
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);///左下角和右上角兩個點表示矩形
            p[k]= {x1,x2,y1,1};
            x[k++]=x1;
            p[k]= {x1,x2,y2,-1};
            x[k++]=x2;
        }
        sort(x,x+k);
        sort(p,p+k,cmp);
        int length=unique(x,x+k)-x;///離散化處理
        build(0,length-2,1);///n個點,n-1個區間,下標從0開始,所以-2
        double res=0;
        for(int i=0; i<k-1; i++)///k條掃描線
        {
            int l=lower_bound(x,x+length,p[i].x1)-x;
            int r=lower_bound(x,x+length,p[i].x2)-x-1;
            if(l<=r)
                update(l,r,p[i].flag,1);
            res+=tree[1].sum*(p[i+1].y-p[i].y);
        }
        printf("Test case #%d\nTotal explored area: %.2f\n\n",t++,res);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章