ZKW線段樹
雜說
最近老是被數據結構血虐,目前就學了 字典樹,樹狀數組,準備學線段樹,看到網上一直在推廣zkw線段樹。所以決定學這個。
zkw線段樹優點有很多,常數小,好寫,等等。不再敘述(因爲我也不懂)
總的來說,就我個人理解,zkw線段樹總共分兩種,一種就是普通維護:需要什麼維護什麼,比如維護區間和,維護區間最大值、最小值等等。另一種就是差分維護:節點存儲與父節點(一開始父節點爲兩個子節點的最小值)的差值。
普通維護
首先是建樹
建樹
建樹自然是要先預分配空間,我的分配方法是先算出位數,比如他有1-n的區間需要維護,那麼先求出 +2,然後
const int N=1<<k;//k就是上面的值,先預先求好
int d[N];
int M;
空間分配好之後就建樹
void build(int n){
for(M=1;M<n;M<<=1);
//M是葉子節點開始儲存的位置
for(int i=M+1;i<=M+n;i++)
scanf("%d",&d[i]);
//以上在建立葉子節點
for(int i=M-1;i;i--)
//d[i]=min(d[i<<1],d[i<<1|1]);
//這樣子算是維護最小值
d[i]=d[i<<1]+d[i<<1|1];//維護和
//以上在建立父節點
}
建樹代碼很簡單就完成
維護
單點修改
x是元素位置,v是元素增量
void Change(int x,int v){
d[x=M+x]+=v;
while(x) d[x>>=1]=d[x<<1]+d[x<<1|1];
}
區間修改
還不會。
查詢
區間和查詢
int Sum(int s,int t,int Ans=0){
for (s=s+M-1,t=t+M+1;s^t^1;s>>=1,t>>=1){//先變開區間
if(~s&1) Ans+=d[s^1];//&1判斷是不是右子樹,^1另一個子樹
if( t&1) Ans+=d[t^1];
}
return Ans;
}
區間和查詢
int Min(int s,int t,int ans=999999){
for (s=s+M-1,t=t+M+1;s^t^1;s>>=1,t>>=1){//先變開區間
if(~s&1) ans=min(ans,d[s^1]);//&1判斷是不是右子樹,^1另一個子樹
if( t&1) ans=min(ans,d[t^1]);
}
return ans;
}