HDU 1542 Atlantis(掃描線)
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
題目連結
給出 個矩形,求所有矩形並集的面積
矩形面積並換句話說就是掃描線裸(板子)題
首先離散化橫座標,將所有矩形的上下邊界按照縱座標升序排序
按照縱座標升序的次序從下向上掃描矩形的面積
按照樣例的影象來理解一下
掃描線第一次從直線 開始掃描,儲存 線段長度,第二次掃描線掃描到 直線,這樣就可以把矩形已經掃過的矩形面積計入結果,再更新線段長度,第三次掃描到 直線,再將掃過的矩形面積計入結果更新線段長度,最後一次掃描到 直線將掃過矩形面積計入結果就可以得出這兩個矩形的面積並了。
掃描線中可以用線段樹維護上一次掃描線掃描到的線段長度的存在位置
推薦一篇具體詳解部落格
線段樹輔助——掃描線法計算矩形面積並
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;
}
相關文章
- HDU 1542 Atlantis (線段樹+離散化+掃描線)
- HDU 1255 覆蓋的面積(線段樹+掃描線+離散化)
- HDU 5862 Counting Intersections(樹狀陣列+掃描線+離散化)陣列
- 淺談掃描線
- 掃描線及其應用
- 掃描所有無線網路
- 【恐怖の演算法】 掃描線演算法
- 全表掃描和全索引掃描索引
- AWVS掃描器掃描web漏洞操作Web
- HDH 1264 Counting Squares (線段樹+掃描線|暴力)
- 掃描器的存在、奧普 掃描器
- win10系統掃描器提示掃描不到掃描器如何解決Win10
- 掃描器
- 掃描王 for Mac專業圖片掃描工具Mac
- win10系統連線掃描器提示“未檢測到掃描器”如何解決Win10
- 什麼是漏洞掃描?漏洞掃描功能有哪些?
- MySQL中的全表掃描和索引樹掃描MySql索引
- 目錄掃描
- 埠掃描器
- python掃描埠Python
- DAST 黑盒漏洞掃描器 第四篇:掃描效能AST
- 電腦掃描檔案怎麼掃描 win10電腦掃描檔案方法介紹Win10
- 全表掃描和全索引掃描繼續(PG-TiDB)索引TiDB
- [20210220]全索引掃描快速索引掃描的邏輯讀.txt索引
- 京東掃描平臺EOS—JS掃描落地與實踐JS
- 掃描行為分析
- 綜合掃描工具
- P2032 掃描
- Nydus 映象掃描加速
- sonar(二)掃描配置
- direasch目錄掃描
- Zenmap(埠掃描工具)
- ReconSage一個快速的線上子域名掃描工具
- Educational Codeforces Round 4 D The Union of k-Segments (掃描線)
- 智慧掃描支援從MySQL例項線上抓取慢SQLMySql
- 圖形學 畫直線 DDA掃描法與中點畫線法
- vuls掃描安裝文件
- Cloudflare網址掃描器Cloud