1. 程式人生 > >HDU-1255 覆蓋的面積 (線段樹 求矩形覆蓋面積)

HDU-1255 覆蓋的面積 (線段樹 求矩形覆蓋面積)

覆蓋的面積

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 6458    Accepted Submission(s): 3286


Problem Description 給定平面上若干矩形,求出被這些矩形覆蓋過至少兩次的區域的面積.



Input 輸入資料的第一行是一個正整數T(1<=T<=100),代表測試資料的數量.每個測試資料的第一行是一個正整數N(1<=N<=1000),代表矩形的數量,然後是N行資料,每一行包含四個浮點數,代表平面上的一個矩形的左上角座標和右下角座標,矩形的上下邊和X軸平行,左右邊和Y軸平行.座標的範圍從0到100000.

注意:本題的輸入資料較多,推薦使用scanf讀入資料.

Output 對於每組測試資料,請計算出被這些矩形覆蓋過至少兩次的區域的面積.結果保留兩位小數.

Sample Input 2 5 1 1 4 2 1 3 3 7 2 1.5 5 4.5 3.5 1.25 7.5 4 6 3 10 7 3 0 0 1 1 1 0 2 1 2 0 3 1
Sample Output 7.63 0.00
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1001;
struct Xpoint{
	double x, l, r;
	int v;
	bool operator < (const Xpoint& e){
		return x < e.x;
	}
}line[maxn << 1];
struct tree{
	int cover;
	double len1, len2;
}c[maxn << 4];
double y[maxn << 2];
void build(int o, int l, int r){
	c[o].cover = c[o].len1 = c[o].len2 = 0;
	if(l == r - 1) return;
	int mid = l + r >> 1;
	build(o << 1, l, mid);
	build(o << 1 | 1, mid, r);
}
void pushup(int o, int l, int r){
	if(c[o].cover > 0){
		c[o].len1 = y[r] - y[l];
	}
	else if(l == r - 1){
		c[o].len1 = 0;
	}
	else{
		c[o].len1 = c[o << 1].len1 + c[o << 1 | 1].len1;
	}

	if(c[o].cover > 1){
		c[o].len2 = y[r] - y[l];
	}
	else if(l == r - 1){
		c[o].len2 = 0;
	}
	else if(c[o].cover == 1){
		c[o].len2 = c[o << 1].len1 + c[o << 1 | 1].len1;   //如果當前被完全覆蓋了一層,那麼不連續的子區間就是第二層覆蓋
	}
	else c[o].len2 = c[o << 1].len2 + c[o << 1 | 1].len2;
}
void add(int o, int l, int r, int L, int R, int v){
	if(l >= R || r <= L) return;
	if(l >= L && r <= R){
		c[o].cover += v;
		pushup(o, l, r);
		return;
	}
	int mid = l + r >> 1;
	add(o << 1, l, mid, L, R, v);
	add(o << 1 | 1, mid, r, L, R, v);
	pushup(o, l, r);
}
int main(){
	int n, T;
	scanf("%d", &T);
	double x1, x2, y1, y2;
	while(T--){
		scanf("%d", &n);
		int tot = 0;
		for(int i = 1; i <= n; ++i){
			scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2);
			line[++tot].x = x1;
			line[tot].l = y1;
			line[tot].r = y2;
			line[tot].v = 1;
			y[tot] = y1;

			line[++tot].x = x2;
			line[tot].l = y1;
			line[tot].r = y2;
			line[tot].v = -1;
			y[tot] = y2;
		}
		build(1, 1, tot);
		sort(y + 1, y + 1 + tot);
		sort(line + 1, line + 1 + tot);
		double ans = 0;
		for(int i = 1; i < tot; ++i){
			y1 = lower_bound(y + 1, y + 1 + tot, line[i].l) - y;
			y2 = lower_bound(y + 1, y + 1 + tot, line[i].r) - y;
			add(1, 1, tot, y1, y2, line[i].v);
			ans += c[1].len2 * (line[i + 1].x - line[i].x);
		}
		printf("%.2lf\n", ans);
	}
}

/*
題意:
1000個矩形,座標範圍1e5,求所有矩形的總覆蓋面積。

思路:
我們把y軸對映到線段樹上,離散化一下,按照x的座標從小到大依次處理所有矩形的平行於y軸的邊。
每一個矩形x座標小的邊表示後面這個區域是被覆蓋的,直到遇到x大的邊結束。那麼我們對於所有矩形
左邊的邊,我們講其加到線段樹的區間上,這樣每處理一條邊,區間上被覆蓋的區間長度可以計算出來,
即這一段y軸的區域是被覆蓋的,再利用x算一下這一段的面積。一直處理完所有面積即可。
這一題需要主要的是需要維護兩次覆蓋,計算覆蓋區間時需要分類討論一下。
*/


相關推薦

HDU-1255 覆蓋面積 (線段 矩形覆蓋面積)

覆蓋的面積 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6458    Accepted Submiss

Hdu 1255 覆蓋面積 線段+矩形面積

繼續面積並學習中。。。(線段樹解決) 題意:給定平面上若干矩形,求出被這些矩形覆蓋過至少兩次的區域的面積 思路:其實跟求矩形面積並的思想是一樣的,只不過在update裡做了一點修改,矩形面積並只需要求至少覆蓋一次的面積,而這題是至少覆蓋兩次的面積,稍微做點修改就可以了 一樣

hdu-1255線段面積並)模板

題目連結:傳送門 思路: (1)建立線段的資訊,每個線段儲存l到r的線段的x位置和y的起始點與終點。 建立線段樹的節點資訊,每個節點代表一個區間的資訊,x表示區間的橫座標的位置,l,r表示縱座標的範圍,flag表示是否標記過,cover表示線段的覆蓋次數。 (2)先將y的位置按照從小到大排序,再將邊按

HDU 5592 ZYB's Premutation (線段逆序對)

題意 給你一組從1到n的排列,表示的是你當前所擁有的逆序對數,現在讓你重新還原這個排列。 思路 我們知道 [1⋅⋅⋅i] [ 1 ·

hdu 1556 塗氣球 線段(區間更新~對區間[x,y]更新,任意節點被更新的次數)

Color the ball Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 29526 &nbs

hdu Minimum Inversion Number(線段逆序數有關問題的一個小歸納)

Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 4904  

hdu 1394(線段逆序數)

題意描述:給你一個有0--n-1數字組成的序列,然後進行這樣的操作,每次將最前面一個元素放到最後面去會得到一個序列,那麼這樣就形成了n個序列,那麼每個序列都有一個逆序數,找出其中最小的一個輸出! 分析:其實只需求出一個序列的逆序數即可,一位第i+1個序列的逆序數為第i

hdu 1542 線段之掃描線之面積

題意:給你n個矩形,求它們的面積,重複的不重複計算 思路:用線段樹的掃描線完成,將X座標離散化後,從下到上掃描矩形,進行各種處理,看程式碼註釋把#include <stdio.h> #include <string.h> #include <

hdu 3333 Turing Tree(線段)

target vector nac ++ uil sim con wrap pro 題目鏈接:hdu 3333 Turing Tree 題目大意:給定一個長度為N的序列。有M次查詢,每次查詢l。r之間元素的總和,同樣元素僅僅算一次。 解題思路:漲姿勢了,線段樹的一

HDU 3016 Man Down(線段)

mes pri microsoft sun lan 遊戲 important -m acm HDU 3016 Man Down 題目鏈接 題意:是男人就下100層的遊戲的簡單版,每次僅僅能從兩端下落。求落地最大血量 思路:利用線段樹能夠處理出每一個線段能來自哪幾

HDU 4902 Nice boat 線段+離線

uil lin ack long wap math.h 離線 線段 str 據說暴力也過了。還傻逼地寫了這麽長。。。 #include <stdio.h> #include <string.h> #include <ma

第四場 hdu 6070 Dirt Ratio (線段+二分)

math sizeof i++ 樹節點 size iostream col 個數 ext http://acm.hdu.edu.cn/showproblem.php?pid=6070 題目大意:給出的序列上的數代表顏色,求子序列中不同數字的個數X與子序列長度Y中,X/Y

hdu1166 敵兵布陣(線段 區間和 更新點)

popu [0 node align 任務 lar bmi bottom tdi 敵兵布陣 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others

HDU 6155 Subsequence Count 線段維護矩陣

input ans ons tom thml other family 卡常 子序列 Subsequence Count Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 256000/256000 K (J

hdu 3397 Sequence operation 線段 區間更新 區間合並

clas cnblogs -- std hdu 查詢 namespace || 兩個 題意: 5種操作,所有數字都為0或1 0 a b:將[a,b]置0 1 a b:將[a,b]置1 2 a b:[a,b]中的0和1互換 3 a b:查詢[a,b]中的1的數量

hdu 1540 Tunnel Warfare 線段 區間合並

freopen uil spa war hdu pri har pre build 題意: 三個操作符 D x:摧毀第x個隧道 R x:修復上一個被摧毀的隧道,將摧毀的隧道入棧,修復就出棧 Q x:查詢x所在的最長未摧毀隧道的區間長度。   1.如果當前區間全是未

hdu 6183 Color it(線段)

php 每次 alt using update -a pac flag aps 題目鏈接:hdu 6183 Color it 題意: 在一個二維平面上有n個操作。 1. x y c 在(x,y)這點上添加一個顏色c。 2. x y1 y2 詢問二維平面[1,x]~[y1,y

HDU.6155.Subsequence Count(線段 矩陣)

open har acm 就是 details efi ron git %d 題目鏈接 首先考慮詢問[1,n]怎麽做 設 f[i][0/1]表示[1,i]以0/1結尾的不同子序列個數 則\(if(A[i]) f[i][1] = f[i-1][0] + f[i-1][1] +

線段逆序對

std con pac clu can -m cnblogs amp ons 思路: 離散化變成一個1-n的數組表示每個數的排名,然後按順序插入各個數排名,並且查詢比它排名大的數的個數。 這個離散化方法還是比較好的,思維難度和代碼難度都比較小。 #include <

HDU - 6315 Naive Operations (線段+思維) 2018 Multi-University Training Contest 2

延遲 給定 要求 lse define 位置 efi operation date 題意:數量為N的序列a和b,a初始全為0,b為給定的1-N的排列。有兩種操作:1.將a序列區間[L,R]中的數全部+1;2.查詢區間[L,R]中的 ∑?ai/bi?(向下取整) 分析:對於一