線段樹的學習之 如何用線段樹計算矩形面積

2021-09-03 08:51:39 字數 4158 閱讀 4873

線段樹是一種靈活的具有區間管理功能的資料結構,其用途跨越離散和線性思想!

我們最常用到的線段樹就是區間求和:

/*

* intervertree.cpp

**  created on: 2012-11-1

*      author: administrator

*/#include

#define m 100

#define mid(a,b) ((a)+(b))>>1

int a[11]=; 

struct treetree[m]; 

/** 建樹

* */

void build(int id,int left,int right) 

int mid=mid(left,right); 

build(id*2,left,mid); 

build(id*2+1,mid+1,right); 

tree[id].sum=tree[id*2].sum+tree[id*2+1].sum; 

} /*

* 更新點

* */

void update(int id,int pos,int key) 

int mid=mid(tree[id].left,tree[id].right); 

pos<=mid?update(id*2,pos,key):update(id*2+1,pos,key); 

tree[id].sum=tree[id*2].sum+tree[id*2+1].sum; 

} /*

* 查詢區間

* */

int query(int id,int left,int right) 

int mid=mid(tree[id].left,tree[id].right); 

if(right<=mid)else

if(left>mid)else 

} int main() 

像上面這樣是最最基礎的線段樹,典型的用空間換時間的做法!而且線段樹也繼承了樹形資料結構一慣的特點:把查詢複雜度從o(n)降低到log(n)。

但是通常用線段樹,我們不會用得這麼直白,會加一些技巧,比如懶操作!懶操作通常用在什麼地方呢?比如更新區間!更新區間的時候,我們一般不會直接去傻呼呼地去更新每乙個點,而是把需要更新的區間先記錄起來,然後如果要用到區間的子區間的時候,我們才去真正更新!

/*

* intervertree.cpp

**  created on: 2012-11-1

*      author: administrator

*/#include

#define m 100

#define mid(a,b) ((a)+(b))>>1

int a[11]=; 

struct treetree[m]; 

/** 建樹

* */

void build(int id,int left,int right) 

int mid=mid(left,right); 

build(id*2,left,mid); 

build(id*2+1,mid+1,right); 

tree[id].sum=tree[id*2].sum+tree[id*2+1].sum; 

} void push_down(int id) 

tree[id].add=0; 

} } 

/** 更新點

* */

void update(int id,int pos,int key) 

int mid=mid(tree[id].left,tree[id].right); 

pos<=mid?update(id*2,pos,key):update(id*2+1,pos,key); 

tree[id].sum=tree[id*2].sum+tree[id*2+1].sum; 

} /*

* 更新區間:把區間[left,right]同時增加key

* */

void update_add(int id,int left,int right,int key) 

int mid=mid(tree[id].left,tree[id].right); 

if(right<=mid)else

if(left>mid)else 

} /*

* 查詢區間

* */

int query(int id,int left,int right) 

int mid=mid(tree[id].left,tree[id].right); 

if(right<=mid)else

if(left>mid)else 

} int main() 

這也是線段樹的基礎操作,一般初學線段樹容易進入乙個誤區,那就是線段樹只能對陣列進行操作,而且線段樹建樹也一定是build(id*2,left,mid),build(id*2+1,mid+1,right); 如果這樣來理解線段樹的話,就大錯特錯了!

線段樹是一種資料結構,而資料結構是我們生活中現實的事物極度抽象的結晶!我們要做的就是學習分析事物,透過現象看本質。這一點說起來很容易,做起來卻極難!

雖然難,但是我們還是要做!那就是線段樹在幾何上的應用。說得更直接一點:

我們怎麼把一條線段用線段樹來表示!比如線段[1,5]怎麼用線段樹來表示:還是像前面建樹那樣:[1,1] [2,2] [3,3] [4,4] [5,5]? 那是行不通嘀!

我們這樣建樹:[1,2][2,3][3,4][4,5],這裡面就涉及到乙個元線段的概念!

而且如果線段的長度很大,或者線段是浮點型資料,那麼我們就需要對線段進行離散化! 離散化的方法也很簡單!比如有三條線段:1.1-2.2   3.3-5.5  8.8-1000.1 我們就可以用乙個長度為6的陣列儲存起來。然後用下標加key的方式來建樹(後面的源**中會展示出來)。這樣的話,一條線段就離散化出來了!

思路分析出來後,可以用一道題來加深一下領悟:線段樹水題poj1151

#include

#include

using

namespace std; 

#define m 1000

#define eps 1e-8

struct treetree[4*m]; 

struct lineline[m]; 

double y[m];//用來離散化y座標軸

int cmp_double(const

double &d1,const

double &d2) 

//比較函式

bool cmp(const line &l1,const line &l2) 

//建樹

void build(int id,int ll,int rr) 

void lenght(int id)else

if(tree[id].ll+1==tree[id].rr)else

tree[id].len=tree[id*2].len+tree[id*2+1].len; 

} //更新樹

void update(int id,line line)else

if(cmp_double(line.y1,tree[2*id+1].lf)>=0)else

if(cmp_double(line.y2,tree[id*2].rf)<=0)else 

lenght(id);//回溯的時候 修改,使根結點的len實時更新

} int main() 

sort(line+1,line+t,cmp); 

sort(y+1,y+t);//線段的離散化

build(1,1,t-1); 

update ( 1, line[1] );//第一條邊一定是入邊

double ans=0.00; 

for(i=2;ians+=tree[1].len*(line[i].x-line[i-1].x); 

update(1,line[i]);//最後一條邊肯定是出邊,不用考慮

} printf("test case #%d\n",++ti); 

printf("total explored area: %.2lf\n\n",ans); 

} return 0; } 

此外,矩形分割也可以求解矩形面積相關的題!

線段樹的學習之 如何用線段樹計算矩形面積(二)

研究了線段樹計算矩形面積的水題poj1151的實現過程,我又好好研究了用線段樹來解決另一道稍微難一點的題 hdu3265,這是09年寧波賽區的一道題,只是在poj1151的基礎上更巧妙了一點!由於題目給出的矩形是回字形,所以我把把乙個回字拆開就可以了,也就是說,hdu3265中插入乙個poster,...

線段樹學習

今天學習了線段樹。是敲了不少 可是感覺還沒有真正理解 先不貼題目。再消化消化。一會兒還有計組實驗。還有那個傲嬌的老師。真是煩。餓。先去吃飯去。一天木有吃。以下 線段樹模板 線段樹的節點 節點包括兩部分資訊,基本域,和資訊域 基本域 左右邊界ld,rd.左右孩子 lc,rc 資訊域 key值,如rmq...

學習線段樹

參考文章 從簡單說起,線段樹其實可以理解成一種特殊的二叉樹。但是這種二叉樹較為平衡,和靜態二叉樹一樣,都是提前已經建立好的樹形結構。針對性強,所以效率要高。這裡又想到了一句題外話 動態和靜態的差別。動態結構較為靈活,但是速度較慢 靜態結構沒有節省記憶體,但速度較快。演算法導論中有涉及區間樹的內容,那...