線段樹之區間更新

2021-07-04 10:48:59 字數 1375 閱讀 1533

為什麼這樣?答案是顯然的。線段樹的查詢和單點更新的時間複雜度是o(logn)的,如果我每次都只是更新乙個節點,再去詢問,那麼複雜度是o(nlogn),這個複雜度是可以接受的,但是如果每次操作我都是更新乙個區間,還是用單點更新去做,那麼複雜度是o(n^2logn),這個複雜度是很大的,一般來說,在acm競賽中是很難接受的或者說是直接摒棄的。所以我們要想辦法去降低複雜度。於是我們就有了區間更新。

以下我們以給某個區間增加x為例講解:

假設我要更新區間[a,b],那我開始由根節點開始遞迴查詢區間,如果發現區間[l,r]完全包含在區間[a,b]裡,我就在這停止,不在繼續更新下去,並在這個節點做標記記錄x,並更新這個節點的sum值。如果下次查詢的時候,碰見標記就開始更新左右兒子,並把自己的標記消除,給兒子做標記,以此類推,直到找到符合查詢的區間為止。

這樣為什麼會快,當節點數很多的時候,如果我每次都把整個操作區間更新到底就會很浪費時間,通過標記,我可以更新到某一層就停止,不必更新到底,這樣當然就很節省時間了。

我們就以這個題意編寫**講解:

題意:在一組數中執行兩種操作:

(1) "c a b c" means adding c to each of aa, aa+1, ... , ab. -10000 ≤ c ≤ 10000.

(2)"q a b" means querying the sum of aa, aa+1, ... , ab.

const int maxn=10005;//假設點的個數

struct seg_tree//為線段樹定義乙個結構體

tree[4*maxn];

//更新父親節點操作

void pushup(int root)

//更新左右兒子操作

void pushdown(int root,int l,int r)

//建樹操作

void build_tree(int root,int r,int l)

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

build_tree(root<<1,l,mid);

build_tree(root<<1|1,mid+1,r);

pushup(root);

}//更新操作

void update(int root,int l,int r,int l,int r,int val )//l,r表示更新的區間的端點,val表示要加的值

if(tree[root].seg!=0) //延遲更新

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

if(l<=mid)

update(root<<1,l,mid,l,r,val);

if(mid>1,sum=0;

if(l<=mid)

sum+=query(root<<1,l,mid,l,r);

if(mid

線段樹之區間更新線段樹

在學習區間更新線段樹之間要先學習單點更新線段樹。情景引入 給乙個長度為n的陣列a,隨機修改區間陣列元素 a l a r 的值,然後求任意區間和。修改操作我們可以想到 for int i l i r i update 但是,這種方法很顯然比較費時,不夠優,所以有了今天要講的區間更新。懶惰標記 在講之前...

線段樹區間更新

在此我們之前學習了線段樹的單點更新 點我 但是現在我們遇到乙個這樣的問題 給出乙個n個元素的陣列a1,a2,an。我們總共進行m次操作。每次操作為下列兩種操作其中一種 1 add l,r,v 將a l a l 1 a r 的值全部增加v。2 query l,r 計算子串行a l a l 1 a r ...

線段樹(區間更新求和)

poj 3468 include using namespace std define max 100100 struct node 求區間長度 int get dis node tree max 3 long long d max 建樹 long long build int left,int r...