HDU 1542 Atlantis(掃描線)

Tony5t4rk發表於2019-02-22

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

題目連結

給出 nn 個矩形,求所有矩形並集的面積

矩形面積並換句話說就是掃描線裸(板子)題

首先離散化橫座標,將所有矩形的上下邊界按照縱座標升序排序

按照縱座標升序的次序從下向上掃描矩形的面積

按照樣例的影象來理解一下

掃描線第一次從直線 ABAB 開始掃描,儲存 ABAB 線段長度,第二次掃描線掃描到 EFEF 直線,這樣就可以把矩形已經掃過的矩形面積計入結果,再更新線段長度,第三次掃描到 DCDC 直線,再將掃過的矩形面積計入結果更新線段長度,最後一次掃描到 HGHG 直線將掃過矩形面積計入結果就可以得出這兩個矩形的面積並了。

掃描線中可以用線段樹維護上一次掃描線掃描到的線段長度的存在位置

推薦一篇具體詳解部落格

線段樹輔助——掃描線法計算矩形面積並

AC程式碼:

#include <bits/stdc++.h>
using namespace std;
typedef double db;
const int maxn = 1e2 + 5;
const db eps = 1e-9;

int Sgn(db Key) {return fabs(Key) < eps ? 0 : (Key < 0 ? -1 : 1);}
int Cmp(db Key1, db Key2) {return Sgn(Key1 - Key2);}

struct Segment {
    db Left, Right;
    db Height;
    int Flag;
};
bool operator < (Segment &Key1, Segment &Key2) {return Cmp(Key1.Height, Key2.Height) < 0;}
vector<Segment> Seg;

vector<db> Pos;

int BinarySearch(db Key) {
    int Res = Pos.size() - 1, Left = 0, Right = Pos.size() - 1;
    while (Left <= Right) {
        int Mid = (Left + Right) >> 1;
        if (Cmp(Pos[Mid], Key) >= 0) {
            Res = Mid;
            Right = Mid - 1;
        }
        else {
            Left = Mid + 1;
        }
    }
    return Res;
}

struct Node {
    int Left, Right;
    int Cnt;
    db Len;
};
Node SGT[maxn << 4];

void PushUp(int Root) {
    if (SGT[Root].Cnt) SGT[Root].Len = Pos[SGT[Root].Right + 1] - Pos[SGT[Root].Left];
    else if (SGT[Root].Left == SGT[Root].Right) SGT[Root].Len = 0.0;
    else SGT[Root].Len = SGT[Root << 1].Len + SGT[Root << 1 | 1].Len;
}

void Build(int Left, int Right, int Root) {
    SGT[Root].Left = Left; SGT[Root].Right = Right;
    SGT[Root].Cnt = 0; SGT[Root].Len = 0.0;
    if (Left == Right) return;
    int Mid = (Left + Right) >> 1;
    Build(Left, Mid, Root << 1);
    Build(Mid + 1, Right, Root << 1 | 1);
    PushUp(Root);
}

void Update(int Left, int Right, int Value, int Root) {
    if (Left <= SGT[Root].Left && Right >= SGT[Root].Right) {
        SGT[Root].Cnt += Value;
        PushUp(Root);
        return;
    }
    int Mid = (SGT[Root].Left + SGT[Root].Right) >> 1;
    if (Right <= Mid) Update(Left, Right, Value, Root << 1);
    else if (Left > Mid) Update(Left, Right, Value, Root << 1 | 1);
    else {
        Update(Left, Mid, Value, Root << 1);
        Update(Mid + 1, Right, Value, Root << 1 | 1);
    }
    PushUp(Root);
}

int Case;
int N;
db X1, Y1, X2, Y2;
db Ans;

int main(int argc, char *argv[]) {
    while (~scanf("%d", &N) && N) {
        Seg.clear(); Pos.clear();
        for (int i = 0; i < N; ++i) {
            scanf("%lf%lf%lf%lf", &X1, &Y1, &X2, &Y2);
            Seg.push_back((Segment){X1, X2, Y1, 1});
            Seg.push_back((Segment){X1, X2, Y2, -1});
            Pos.push_back(X1); Pos.push_back(X2);
        }
        sort(Seg.begin(), Seg.end());
        sort(Pos.begin(), Pos.end(), [&](db Key1, db Key2) {return Cmp(Key1, Key2) < 0;});
        int Cur = 1;
        for (int i = 1; i < (int)Pos.size(); ++i)
            if (Cmp(Pos[i], Pos[i - 1]) != 0)
                Pos[Cur++] = Pos[i];
        Pos.erase(Pos.begin() + Cur, Pos.end());
        Build(0, (int)Pos.size(), 1);
        Ans = 0.0;
        for (int i = 0; i < (int)Seg.size() - 1; ++i) {
            int Left = BinarySearch(Seg[i].Left), Right = BinarySearch(Seg[i].Right);
            Update(Left, Right - 1, Seg[i].Flag, 1);
            Ans += (Seg[i + 1].Height - Seg[i].Height) * SGT[1].Len;
        }
        printf("Test case #%d\n", ++Case);
        printf("Total explored area: %.2lf\n\n", Ans);
    }
    return 0;
}

相關文章