區間更新是指更新某個區間內的葉子節點的值,因為涉及到的葉子節點不止乙個,而葉子節點會影響其相應的非葉父節點,那麼回溯需要更新的非葉子節點也會有很多,如果一次性更新完,操作的時間複雜度肯定不是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主要是 求出在給定區間...