線段樹本質上是一棵二叉搜尋樹(體現在查詢階段),與普通的二叉樹不一樣,這個二叉樹有點特別:用left和right來表示乙個區間,即 [left, right],而其值val,則用來表徵這個區間的某些特徵,例如:區間最大值,區間最小值,區間和;並且容易知道,當left和right相等時,代表葉結點,其值就是某個陣列當前位置的值。
一棵區間為[1, 5]上的線段樹
線段樹在處理某些問題時是非常方便的,乙個經典的問題是:給你乙個陣列,總共n個值(陣列從1到n排列),然後給你乙個區間 [l, r],對於每次查詢,給出區間 [l, r]的和(或者最大值,最小值)
聰明的小夥伴一定會馬上想到用字首和來處理這個問題,是的,字首和在預處理階段為o(n)複雜度,而每次查詢只需要o(1),對於這種靜態問題是十分方便的,但是,如果我們在上面的問題中加上 「每次隨機更新陣列中的某個值」 這一條件時,維護字首和的開銷其實是十分巨大的,因為對於每次修改,你不得不對字首和進行o(n)的更新,如果資料量過大,這種方式是肯定不行的。所以,我們採用線段樹這一資料結構來解決這個問題
典型的線段樹可以採用如下定義:
struct treenode
tree[4*n];
以下為線段樹的三個操作,建樹,查詢,更新
注:**以求區間和為例
void build(int root,int l,int r)//建樹
int mid=(l+r)/2;
build(2*root,l,mid);//左子樹
build(2*root+1,mid+1,r);//右子樹
tree[root].val=tree[2*root].val+tree[2*root+1].val;//求和
}
int query(int root,int l,int r)//查詢[l,r]的和
int mid=(tree[root].left+tree[root].right)/2;
if(mid>=r)
return query(2*root,l,r);//在左子樹查詢
else
if(mid+1
<=l)
return query(2*root+1,l,r);//在右子樹查詢
return query(2*root,l,mid)+query(2*root+1,mid+1,r);//跨區間查詢
}
void update(int root,int pos,int val)//更新pos位置的值為val
int mid=(tree[root].left+tree[root].right)/2;
if(pos<=mid)
update(2*root,pos,val);
else update(2*root+1,pos,val);
tree[root].val=tree[2*root].val+tree[2*root+1].val;//更新和
}
線段樹每次查詢和更新操作時,其複雜度為o(logn),這對於我們來說,是較為理想的。
應用問題:
第一行給出n,m,分別為陣列元素的個數以及請求個數
第二行給出n個數,
隨後m行,每行給出乙個操作:opt x y
當opt = 1,更新陣列中x位置的值為y
當opt = 2,輸出[x, y]的區間和
注:下標從1開始
/* test case
8 41 2 3 4 5 6 7 8
1 2 0
2 1 8
1 8 0
2 2 2
*//*output340
*/
#include
#define n 1024
using
namespace
std;
struct treenode
tree[4*n];
int arr[n];
void build(int root,int l,int r)
int mid=(l+r)/2;
build(2*root,l,mid);
build(2*root+1,mid+1,r);
tree[root].val=tree[2*root].val+tree[2*root+1].val;
}int query(int root,int l,int r)
int mid=(tree[root].left+tree[root].right)/2;
if(mid>=r)
return query(2*root,l,r);
else
if(mid+1
<=l)
return query(2*root+1,l,r);
return query(2*root,l,mid)+query(2*root+1,mid+1,r);
}void update(int root,int pos,int val)
int mid=(tree[root].left+tree[root].right)/2;
if(pos<=mid)
update(2*root,pos,val);
else update(2*root+1,pos,val);
tree[root].val=tree[2*root].val+tree[2*root+1].val;
}int main()
HDU1754 《線段樹建立,查詢,更新》
the reason of failure 1 又一次被cin的速度坑了!注意大資料要用scanf的輸入方法啊。learning 1 線段樹是用來幹嘛的,是可以找區間最大最小值或者和之類的值的。thinking 每次這個線段的max1取max max1,weight 也就是判斷改變的這個值,是否大於...
線段樹的構建,查詢與更新
線段樹是一種二叉搜尋樹,與區間樹相似,它將乙個區間劃分成一些單元區間,每個單元區間對應線段樹中的乙個葉結點。使用線段樹可以快速的查詢某乙個節點在若干條線段 現的次數,時間複雜度為o logn 而未優化的空間複雜度為2n,實際應用時一般還要開4n的陣列以免越界,因此有時需要離散化讓空間壓縮。想要理解線...
線段樹的建樹 更新 查詢操作
模板題sdut oj 3771 陣列計算機 description blue 有乙個神器的機器,這個機器可以讀入乙個陣列,並按照使用者要求快速地進行陣列的處理和計算,它支援如下兩種操作 操作 1 把陣列中第 p 個元素的值增加 v。操作 2 計算陣列中 l,r 區間內所有數的和。這個機器就是這麼的神...