一般線段樹做區間修改操作時,先是找到目標區間,然後修改該區間,並打下延遲標記,最後從目標區間自底向上,更新所有包含目標區間的區間的值(即pushup)。當該區間子節點被訪問前,pushdown下推標記。
這種維護區間的方式存在一點點弊端。例如用這種方式寫一棵可持久化線段樹,因為每次pushdown都相當於繼續之前延遲了的更新操作,所以得開新的節點,然後開著開著可能就爆記憶體了…..
一種更好的方法就是用標記永久化。 從字面意思就可以知道,永久化的標記是不會變的,這個不變是不會變小(一般的那種 pushdown的時候標記都清0了)。
實現過程:update[l,r]時,把所有包含[l,r]的區間更新(顯然修改[l,r]能影響到的就是這些區間),然後在[l,r]上打上標記;query[l,r]時,自頂向下找區間[l,r],統計從根到目標節點的路上標記的和,結果就是目標區間的值加上路徑上所有標記的影響。
優勢:不用pushdown,**短了,且可持久化的時候不用開新的節點;與下推標記的寫法相比略快一點
下面附上poj3468和hdu4348的**
poj3468
#include
#include
using
namespace
std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const
int maxn = 100000+10;
typedef
long
long ll;
ll t[maxn<<2],lazy[maxn<<2];
void build(int l,int r,int rt)
int m = l+r >> 1;
build(lson);
build(rson);
t[rt] = t[rt<<1] + t[rt<<1|1];
}void update(int l,int r,int val,int l,int r,int rt)
int m = l + r >> 1;
if(r<=m)
update(l,r,val,lson);
else
if(l>m)
update(l,r,val,rson);
else update(l,m,val,lson), update(m+1,r,val,rson);
}ll query(int l,int r,int l,int r,int rt,int add)
int n,q;
int x,y;
ll z;
char str[10];
int main()
else
}return
0;}
hdu4348
#include
#include
#include
using
namespace
std;
const
int maxn = 1e5 + 5;
typedef
long
long ll;
int lazy[maxn*30],ls[maxn*30],rs[maxn*30],n,q;
ll t[maxn*30];
int tot,root[maxn],nowroot;
#define lson l,m,ls[now]
#define rson m+1,r,rs[now]
void build(int l,int r,int &now)
int m = l + r >> 1;
build(lson);
build(rson);
t[now] = t[ls[now]] + t[rs[now]];
//printf("t[%d] = %lld\n",now,t[now]);
}void update(int l,int r,int val,int l,int r,int &now,int lst)
int m = l + r >> 1;
if(r<=m)
update(l,r,val,lson,ls[lst]);
else
if(l>m)
update(l,r,val,rson,rs[lst]);
else
update(l,m,val,lson,ls[lst]), update(m+1,r,val,rson,rs[lst]);
}ll query(int l,int r,int l,int r,int now,int add)
void init()
int main()}}
}
線段樹標記永久化
對於樹套樹,主席樹等使用到線段樹的比較複雜的資料結構,如果區間修改的話,打標記後pushdown或者pushup是很難做到的完全不行吧 所以這個時候,乙個神奇的東西誕生了。線段樹標記永久化,維護乙個標記,假設為cov,再維護乙個sum 假設修改區間 ql,qr 全部加上v 和平常一樣,到這個區間後c...
線段樹 永久化標記優化
誕生 正常的線段樹的改段求段都離不開lazy標記,lazy標記維護時要及時的更新,即人們熟知的pushdown函式。那麼能不能避免這麼多次無意義的pushdown操作呢?他就是 標記永久化。原理 舉個最簡單的例子,線段樹區間修改,求區間最大值。這時的lazy存的是當前這一段待下傳的最大值,也就是說這...
線段樹標記永久化模板
題目如下 poj 3468 輸入整數n,q,然後輸入n個數的序列,再然後輸入q條詢問,詢問有兩種型別 q l r 代表列印出區間 l,r 的和 c l r v 代表區間 l,r 區間的數都加v 基本思路 這裡選擇線段樹,主要是為了練習線段樹標記永久化 下面介紹線段樹標記永久化 如下 include ...