線段樹-快速總結-算法筆記

主要的目的是記錄一哈二維線段樹,在此之前先簡單總結一下一維線段樹。

線段樹

線段樹顧名思義,處理線段(或者稱爲區間)的整體屬性的一種數據結構。
主要操作爲-範圍更新與查詢,時間複雜度爲logn級別的。

構建過程爲:
這棵樹將所定範圍(區間)不斷進行二分,直至只包含一個值作爲葉節點。
其他的非葉節點表示線段經過二分過後的某個區間。

更新操作:
將所給的區間,與線段樹節點區間比較
所給區間包含樹節點區間,則處理。
區間與樹節點區間不相交,丟掉。
區間有交叉,遞歸到子節點,進行相同步驟。

//有lazy標記優化
目的是當所給區間包含樹節點,不進行子節點的處理,但是做個標記(另開個數組或者加個屬性),表示這些節點是要處理的,但是我們不進行處理,等到查詢的時候進行處理。

查詢操作:
類似
有lazy標記的,則處理後續節點,清除lazy標記,給子節點標記上,逐層進行,如果到了最後一層則不用管lazy標記了。

二維線段樹

基本上是樹套樹,適合矩陣查詢。時間複雜度是logn^2
基本上是在第一層線段樹的基礎上,每個節點的屬性是另一個線段樹。

基本上更新是先按一維查詢,
三種情況中
找到包含的情況後(一維線段樹有講),進行第二維的更新。

下面的代碼是更新操作

const int MAX_N=1<<9; //500個
#define THRES 2*MAX_N
int n,data[2*MAX_N][2*MAX_N];
//省遞歸參數
int yy1,yy2,vv;

void changey(int y1,int y2,int iy,int l,int r,int ix){
    int mid=l+r>>2;
    //y1<y2
    if(y2<l || y1>=r){
        return;
    }else if(y1<=l && y2>=r){
        //todo change data
        //data[ix][iy]=vv;
        std::function<void(int x)> push_down;
        push_down=[&push_down,&ix](int iy){
            if(iy<THRES){
                data[ix][iy]=vv;
                push_down(iy*2);
                push_down(iy*2+1);
            }
        };
        push_down(iy);
        
    }else{
        int ny1=max(y1,l);
        int ny2=min(y2,r-1);
        changey(ny1,ny2,2*iy,l,mid,ix);
        changey(ny1,ny2,2*iy+1,mid,r,ix);
    }
}

void changex(int x1,int x2,int ix,int l,int r){
    int mid=l+r>>2;
    //x1<=x2
    if(x2<l ||x1>=r){
        return;
    }else if(x1<=l && x2>=r){
        //todo
        //change y
        //changey(yy1, yy2, 1, 0, 501,ix);
        //更新完後面的
        
        std::function<void(int x)> push_down,push_down_copy;
        push_down=[&push_down](int ix){
            if(ix<THRES){
                changey(yy1, yy2, 1, 0, 501,ix);
                push_down(ix*2);
                push_down(ix*2+1);
            }
        };
        push_down(ix);
        
        /*
        changey(yy1, yy2, 1, 0, 501,ix);
        push_down_copy=[&push_down_copy](int ix){
            if(ix<THRES){
                copy(begin(data[ix]), end(data[ix]), begin(data[2*ix]));
            }
        };*/
        
        return;
    }else{
        int nx1=max(x1,l);
        //減1,前開後閉[)
        int nx2=min(x2,r-1);
        changex(nx1,nx2,2*ix,l,mid);
        changex(nx1,nx2,2*ix+1,mid,r);
    }
}

//init range 0 - 500
void update(int x1,int x2,int y1,int y2,int v){
    yy1=y1;
    yy2=y2;
    vv=v;
    changex(x1,x2,1,0,501);
}

查詢類似


int queryx(int x1,int l,int r,int ix){
    int mid=l+r>>2;
    if(x1==l==r){
        return ix;
    }
    if(x1<mid){
        return queryx(x1,l,mid,2*ix);
    }else{
        return queryx(x1, mid, r, 2*ix+1);
    }
}

int queryy(int y1,int l,int r,int ix,int iy){
    if(y1==l==r){
        return data[ix][iy];
    }
    int mid=l+r>>2;
    if(y1<mid){
        return queryy(y1,l,mid,ix,2*iy);
    }else{
        return queryy(y1,mid,r,ix,2*iy+1);
    }
}


int query(int x1,int y1,int l,int r){
    auto ix=queryx(x1, 0, 500, 1);
    int v=queryy(y1, 0, 500, ix, 1);
    return v;
}

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