ACM訓練日誌29 線段樹的區間更新

2021-09-05 09:14:08 字數 2702 閱讀 1685

區間更新是指更新某個區間內的葉子節點的值,因為涉及到的葉子節點不止乙個,而葉子節點會影響其相應的非葉父節點,那麼回溯需要更新的非葉子節點也會有很多,如果一次性更新完,操作的時間複雜度肯定不是o(lgn),例如當我們要更新區間[0,3]內的葉子節點時,需要更新出了葉子節點3,9外的所有其他節點。為此引入了線段樹中的延遲標記概念,這也是線段樹的精華所在。

延遲標記:每個節點新增加乙個標記,記錄這個節點是否進行了某種修改(這種修改操作會影響其子節點),對於任意區間的修改,我們先按照區間查詢的方式將其劃分成線段樹中的節點,然後修改這些節點的資訊,並給這些節點標記上代表這種修改操作的標記。在修改和查詢的時候,如果我們到了乙個節點p,並且決定考慮其子節點,那麼我們就要看節點p是否被標記,如果有,就要按照標記修改其子節點的資訊,並且給子節點都標上相同的標記,同時消掉節點p的標記。

const int infinite = int_max;

const int maxnum = 1000;

struct segtreenode

segtree[maxnum];//定義線段樹

/*功能:構建線段樹

root:當前線段樹的根節點下標

arr: 用來構造線段樹的陣列

istart:陣列的起始位置

iend:陣列的結束位置

*/void build(int root, int arr, int istart, int iend)}/*

功能:當前節點的標誌域向孩子節點傳遞

root: 當前線段樹的根節點下標

*/void pushdown(int root)}/*

功能:線段樹的區間查詢

root:當前線段樹的根節點下標

[nstart, nend]: 當前節點所表示的區間

[qstart, qend]: 此次查詢的區間

*/int query(int root, int nstart, int nend, int qstart, int qend)

/*功能:更新線段樹中某個區間內葉子節點的值

root:當前線段樹的根節點下標

[nstart, nend]: 當前節點所表示的區間

[ustart, uend]: 待更新的區間

addval: 更新的值(原來的值加上addval)

*/void update(int root, int nstart, int nend, int ustart, int uend, int addval)

pushdown(root); //延遲標記向下傳遞

//更新左右孩子節點

int mid = (nstart + nend) / 2;

update(root*2+1, nstart, mid, ustart, uend, addval);

update(root*2+2, mid+1, nend, ustart, uend, addval);

//根據左右子樹的值回溯更新當前節點的值

segtree[root].val = min(segtree[root*2+1].val, segtree[root*2+2].val);

}

使用方法步驟:

1、build(1, n); 建立乙個葉子節點為n個的線段樹

2、update(l, r, val, 1, n); 更新線段樹中[l, r]區間每個值都增加val

3、query(l, r, 1, n); 查詢[l ,r]區間值之和

###tips

請注意update的目的是增減還是替換,根據情況修改update函式和pushup函式

建出來的樹為空樹,預設每個點值都為0,需要自行將值update上去,或者修改build中sum[rt]=0;為輸入操作scanf("%d",sum+rt);

課作為模板使用:

#define lson l,m,rt<<1

#define rson m+1,r,rt<<1|1

const int maxn = 100005;

int add[maxn<<2],sum[maxn<<2];

void pushup(int rt)

void pushdown(int rt,int m)

}void build(int l,int r,int rt=1)

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

build(lson);

build(rson);

pushup(rt);

}void update(int l,int r,int c,int l,int r,int rt=1)

pushdown(rt , r - l + 1);

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

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

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

pushup(rt);

}int query(int l,int r,int l,int r,int rt=1)

pushdown(rt , r - l + 1);

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

int ret = 0;

if (l <= m) ret += query(l , r , lson);

if (m < r) ret += query(l , r , rson);

return ret;

}

ACM訓練日誌

今天的比賽我們隊倆大佬出了倆題,後來過了時間又補了f題,總的來說我覺得今天訓練不簡單,被d題整的心態有點炸,後來于衡a掉了,貪心字首和,仔細看了隊友的 還是很有啟發的,附上原題和隊友的 原題 ac include using namespace std const int maxn 4e5 10 t...

ACM訓練日誌27 線段樹建立和查詢

線段樹是一種二叉搜尋樹,與區間樹相似,它將乙個區間劃分成一些單元區間,每個單元區間對應線段樹中的乙個葉結點。對於線段樹中的每乙個非葉子節點 a,b 它的左兒子表示的區間為 a,a b 2 右兒子表示的區間為 a b 2 1,b 因此線段樹是平衡二叉樹,最後的子節點數目為n,即整個線段區間的長度.使用...

ACM訓練日誌6

數字dp的訓練賽結束了,但是自我感覺我的水平還是差遠了,光從解題數量也看的出來,而且做出來的題都是裡面比較水的題目,難一點的還是做不出來。其中有兩個數字dp 二分的題目,兩個題很相像,能做出來一道另一道乙個道理也就做出來了,但是我折騰了好久,都沒出,樣例不過。目前認識的數字dp主要是 求出在給定區間...