矩形面積並(POJ 1151)

2021-08-14 18:52:02 字數 3388 閱讀 5521

給你n個矩形,求這些矩陣的面積並n

「掃瞄線思路」+離散化+線段樹維護

關於掃瞄線:可以看下這篇部落格

關於離散化

由於座標範圍較大,需要使其更「緊密」,這樣才能用線段樹處理

離散化的核心思想就是相對大小不變且能通過現在的值確定之前的值

所以離散化的方法就是(以y軸座標為例) 將y軸座標塞入id陣列(2*n個)排序

將之前每個事件的y軸座標替換為在id陣列中的下標 (二分去找)這樣就完成了離散化

關於線段樹維護

將事件分成兩類,即入事件和出事件。

對於入事件,我們將區間cov值+1,即對應區間標記+1

對於出事件,我們將區間cov值-1 ,即對應區間標記-1

每一次處理過乙個事件後,對於總區間,我們維護的sum[1]的值為那些標記不為0的區間所對應的長度,這些長度可以作為面積並的長,高即為ev

t[i+

1].h

−evt

[i].

h 當再處理乙個事件時,如果它是出事件,那麼自然會更新對應區間cov的值-1,剩下的不為0的區間又可以作為面積並的長,以此類推……

兩種不同的寫法

注意到,這裡處理的是區間,即最小單位是長度為1的區間(離散化後)。但是一般的線段樹其葉子節點就表示那個點,而不是區間。

舉個例子,比如[3,4]區間+1,一般寫法會將葉子節點3和葉子節點4的值+1,再pushup。但這裡我們沒法處理這樣跨結點的區間,因為要麼兩邊都加(超了),要麼都return (少了)。即對於點線段樹遞迴區間時要採用左閉右開的方法。

所以有兩種寫法:

下面是兩種方法的**實現,細節見**注釋
//沿y軸方向掃瞄  對x軸座標離散化後用線段樹維護

#include

#include

#include

#include

#define lson l,m,rt<<1

#define rson m+1,r,rt<<1|1//這裡葉子節點還是表示點而不是區間,這也是通常的做法

using namespace std;

typedef

long

long ll;

const

int maxn=100010*2;//注意"事件是矩形數量的兩倍"

int n;

int cov[maxn<<2];//區間覆蓋情況

double

id[maxn],sum[maxn<<2];//id用於離散化

struct event//必須要加

event(double l,double r,double h,int f):l(l),r(r),h(h),f(f){}

bool operator < (const event & rhs) const

}evt[maxn];

void pushup(int l,int r,int rt)

void update(int l,int r,int c,int l,int r,int rt)

int m=(l+r)>>1;

if(l<=m) update(l,r,c,lson);

if(r>m) update(l,r,c,rson);

pushup(l,r,rt);

}int main()

sort(evt+1,evt+2*n+1);

sort(id+1,id+2*n+1);

int m=unique(id+1,id+2*n+1)-id-1;//其實可以不去重

memset(cov,0,sizeof(cov));

memset(sum,0,sizeof(sum));

double ans=0;

for(int i=1;i<2*n;i++)

printf("test case #%d\ntotal explored area: %.2f\n\n",cas++, ans);

}return

0;}

//1是沿y軸方向掃瞄  對x軸座標離散化後用線段樹維護

#include

#include

#include

#include

#define lson l,m,rt<<1

#define rson m,r,rt<<1|1//這裡葉子節點表示最小區間

using namespace std;

typedef

long

long ll;

const

int maxn=100010*2;//注意"事件是矩形數量的兩倍"

int n;

int cov[maxn<<2];//區間覆蓋情況

double

id[maxn],sum[maxn<<2];//id用於離散化

struct event//必須要加

event(double l,double r,double h,int f):l(l),r(r),h(h),f(f){}

bool operator < (const event & rhs) const

}evt[maxn];

void pushup(int l,int r,int rt)

void update(int l,int r,int c,int l,int r,int rt)

int m=(l+r)>>1;

if(l//注意這裡是< 沒有等於號

if(r>m) update(l,r,c,rson);

pushup(l,r,rt);

}int main()

sort(evt+1,evt+2*n+1);

sort(id+1,id+2*n+1);

int m=unique(id+1,id+2*n+1)-id-1;//其實可以不去重

memset(cov,0,sizeof(cov));

memset(sum,0,sizeof(sum));

double ans=0;

for(int i=1;i<2*n;i++)

printf("test case #%d\ntotal explored area: %.2f\n\n",cas++, ans);

}return

0;}

這裡都是沿y軸方向掃瞄 對x軸座標離散化後用線段樹維護的;當然也可以反過來

POJ1151 離散化求矩形面積的並

第一道離散化的題目,雖然是水題,不過還是很高興。include include include using namespace std struct rect define max 103 1 rect a max 1 double x max y max bool flag max max int...

poj 1151 線段樹求矩形面積的並

其實掌握了基本思路就沒問題了,不過還是能學到一些思想的。比如說,離散化,掃瞄線,計算幾何裡的線段樹建樹的不同。尤其是要注意離散化,許多線段樹問題都要離散化才能做,否則超記憶體。這題的離散化就是把座標的範圍,用存放它們的下標來表示。這樣一來範圍就小多了,然後每個節點表示的範圍就是這兩個下標 存放的對應...

poj 1151矩形面積並 線段樹

title poj 1151矩形面積並 線段樹 date 2018 10 30 22 35 11 tags 線段樹問題裡的另乙個問題,矩形面積並,之前看lazy更新時看到下面這個的講解,一大堆文字還有一大堆的圖,當時果斷跳過,今天花了一下午加一晚上的時間看了看這塊知識,然後嘗試自己寫出 算是簡單的了...