zkw線段樹

ZKW線段樹


雜說


    最近老是被數據結構血虐,目前就學了 字典樹,樹狀數組,準備學線段樹,看到網上一直在推廣zkw線段樹。所以決定學這個。
    zkw線段樹優點有很多,常數小,好寫,等等。不再敘述(因爲我也不懂)
    總的來說,就我個人理解,zkw線段樹總共分兩種,一種就是普通維護:需要什麼維護什麼,比如維護區間和,維護區間最大值、最小值等等。另一種就是差分維護:節點存儲與父節點(一開始父節點爲兩個子節點的最小值)的差值。

普通維護

    首先是建樹

建樹

    建樹自然是要先預分配空間,我的分配方法是先算出位數,比如他有1-n的區間需要維護,那麼先求出int(log2n) +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;
}

未完待續,正在學習


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章