1. 程式人生 > 其它 >亞特蘭蒂斯

亞特蘭蒂斯

題目描述

有幾個古希臘書籍中包含了對傳說中的亞特蘭蒂斯島的描述。
其中一些甚至包括島嶼部分地圖。
但不幸的是,這些地圖描述了亞特蘭蒂斯的不同區域。
您的朋友 Bill 必須知道地圖的總面積。
你自告奮勇寫了一個計算這個總面積的程式。

輸入格式

輸入包含多組測試用例。
對於每組測試用例,第一行包含整數 n,表示總的地圖數量。
接下來 n 行,描繪了每張地圖,每行包含四個數字 x1,y1,x2,y2(不一定是整數),(x1,y1) 和 (x2,y2) 分別是地圖的左上角位置和右下角位置。
注意,座標軸 x 軸從上向下延伸,y 軸從左向右延伸。
當輸入用例 n=0 時,表示輸入終止,該用例無需處理。

輸出格式

每組測試用例輸出兩行。
第一行輸出 Test case #k,其中 k 是測試用例的編號,從 1 開始。
第二行輸出 Total explored area: a,其中 a 是總地圖面積(即此測試用例中所有矩形的面積並,注意如果一片區域被多個地圖包含,則在計算總面積時只計算一次),精確到小數點後兩位數。
在每個測試用例後輸出一個空行。

資料範圍

\(1≤n≤10000,0≤x1<x2≤100000,0≤y1<y2≤100000\)
注意,本題 n 的範圍上限加強至 10000。

輸入樣例:
2
10 10 20 20
15 15 25 25.5
0
輸出樣例:
Test case #1
Total explored area: 180.00 
思路

假設給的影象是這樣。

實際要求的面積是這樣

我們先來想暴力的思路。假設每個座標都是整數,那就是一行一行的數有多少個格子被塗上了顏色。
這樣顯然會TLE,但是我們的思路不變,想想怎麼才能優化這個數格子的步驟。
首先我們想到每個豎線到下一個豎線前它的len值肯定是不變的,那麼我們就不需要一行一行的數了,只需要在對於每一道豎線那數一下,然後乘上豎線之間的差。
那麼接下來的問題是怎麼能快速算出每一個豎線所對應的長度。由於在每個x那都可能修改還有查詢,這樣大量的區間查詢與修改操作,我們難免會想到線段樹。
那麼我們就把初始每個矩形的左邊標記為+1表示矩形開始,右邊標記為-1表示這個矩形結束。被標記為正數的區域即線段長度。
這題所採用的x,y都是double型別的需要我們進行離散化。
接下來面臨的問題是怎麼去維護這個線段樹。
我們不需要查詢函式,因為每次的查詢都是對於整個區間查詢長度,即\(tr[1].len\)

,由此我們也省略了\(pushdown()\)函式。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int N = 1e6 + 10;

struct Seg{
	double x, y1, y2;
	int k;
	bool operator < (const Seg& t) const {
		return x < t.x;
	}
}s[N];
struct Node{
	int l, r;
	int cnt;
	double len;
}tr[N];

vector<double> all;

inline int find(double y){
	return lower_bound(all.begin(), all.end(), y) - all.begin();
}
void pushup(int u){
	if(tr[u].cnt)
		tr[u].len = all[tr[u].r + 1] - all[tr[u].l];
	else if(tr[u].l != tr[u].r)
		tr[u].len = tr[u << 1].len + tr[u << 1 | 1].len;
	else tr[u].len = 0;
}
void build(int u, int l, int r){
	tr[u] = { l, r, 0, 0 };
	if(l != r){
		int mid = l + r >> 1;
		build(u << 1, l, mid);
		build(u << 1 | 1, mid + 1, r);
	}
}
void modify(int u, int l, int r, int d){
	if(tr[u].l >= l && tr[u].r <= r)tr[u].cnt += d;
	else {
		int mid = tr[u].l + tr[u].r >> 1;
		if(l <= mid)modify(u << 1, l, r, d);
		if(r > mid)modify(u << 1 | 1, l, r, d);
	}
	pushup(u);
}
int main(){
	int n, t = 1;
	while(scanf("%d", &n), n){
		all.clear();
		for(int i = 0, j = 0; i < n; i++){
			double x1, x2, y1, y2;
			scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2);
			s[j++] = { x1, y1, y2, 1 };
			s[j++] = { x2, y1, y2, -1 };
			all.push_back(y1), all.push_back(y2);
		}
		sort(all.begin(), all.end());
		all.erase(unique(all.begin(), all.end()), all.end());
		build(1, 0, all.size() - 2);
		sort(s, s + n * 2);
		double res = 0;
		for(int i = 0; i < n * 2; i++){
			if(i)res += tr[1].len * (s[i].x - s[i - 1].x);
			modify(1, find(s[i].y1), find(s[i].y2) - 1, s[i].k);
		}
		printf("Test case #%d\nTotal explored area: %.2lf\n\n", t++, res);
	}
	return 0;
}