二維線段樹模板


title: 二維線段樹模板
date: 2018-10-31 15:21:44
tags:
- 二維線段樹
categories: “算法”

這個模板是根據HDU-4819編寫的。功能是用二維線段樹進行

二維點修改和區間查詢最小者和最大值。

二維線段樹的思想跟一維一樣,只不過一維是二分二叉樹,二維

是四分四叉樹。具體實現看代碼。

#include<bits/stdc++.h>
using namespace std;
const int LOGN = 10;
const int MAXN = (1<<LOGN);
const int MAXNODES = (3*(1<<(2*LOGN)) + 100);
const int MAX_VAL = 0x3f3f3f3f;
const int MIN_VAL = -0x3f3f3f3f;
#define son(x) (p*4-2+x)
//表示最大值,最小值信息的結構體
struct dataInfo{
    short posx, posy;
    int val;
    dataInfo(){
        posx = posy = val = -1;
    }

    dataInfo(short _posx, short _posy, int _val){
        posx=_posx;
        posy=_posy;
        val=_val;
    }

};
//樹的節點
struct treeNode{
    dataInfo maxv, minv;
    void reset(){
        maxv = dataInfo(0, 0, INT_MIN);
        minv = dataInfo(0, 0, INT_MAX);
    }
}nodes[MAXNODES];
//得到節點的指針
treeNode* getNode(int id){
    return &nodes[id];
}
//表示x、y的範圍
struct Interval{
    int l, r;
    Interval(){}
    Interval(int _l, int _r){
        l=_l; r=_r;
    }
    int mid(){
        return (l+r)>>1;
    }
    int len(){
        return r-l+1;
    }
    Interval left(){
        return Interval(l, mid());
    }
    Interval right(){
        return Interval(mid()+1, r);
    }
    bool isIntersectWith(Interval& tarI){//判斷兩區間是否相交
        return !(l>tarI.r || r<tarI.l);
    }
    bool isInclude(Interval& tarI){//是否包含tarI區間
        return l<=tarI.l && tarI.r<=r;
    }
    bool in(int v){//是否包含v點
        return l<=v && v<=r;
    }

};
//建樹
void build_segtree(int p, Interval xI, Interval yI){
    if(xI.len()<=0 || yI.len()<=0){
        return;
    }
    treeNode* now=getNode(p);
    now->reset();
    if(xI.len() == 1 && yI.len()==1){
        return;
    }
    //分別爲左上、右上、左下、右下的矩形區間
    build_segtree( son(0), xI.left(), yI.left() );
    build_segtree( son(1), xI.right(), yI.left() );
    build_segtree( son(2), xI.left(), yI.right() );
    build_segtree( son(3), xI.right(), yI.right() );
}
//點修改
bool insert_segtree(int p, Interval xI, Interval yI, int x, int y, int val){
    if(xI.len() <= 0 || yI.len()<=0){
        return false;
    }
    if(!xI.in(x) || !yI.in(y) ){
        return true;
    }
    treeNode *now = getNode(p);
    if(xI.len()==1 && yI.len()==1){
        now->maxv=now->minv =dataInfo(x, y, val);
        return true;
    }

    bool isvalid[4];
    isvalid[0]=insert_segtree( son(0), xI.left(), yI.left(), x, y, val);
    isvalid[1]=insert_segtree( son(1), xI.right(), yI.left(), x, y, val);
    isvalid[2]=insert_segtree( son(2), xI.left(), yI.right(), x, y, val);
    isvalid[3]=insert_segtree( son(3), xI.right(), yI.right(), x, y, val);

    now->reset();
	
    for(int i=0; i<4; i++){
        if(!isvalid[i]) continue;//只對有效的區間修改
        treeNode *sonNode =getNode(son(i));
        now->maxv=sonNode->maxv.val > now->maxv.val?sonNode->maxv : now->maxv;
        now->minv=sonNode->minv.val < now->minv.val?sonNode->minv : now->minv;
    }
    return true;
}

void query_segtree(int p, Interval xI, Interval yI, Interval tarXI, Interval tarYI, treeNode& ans){

    if(xI.len()<=0 || yI.len()<=0){
        return;
    }
    if(!tarXI.isIntersectWith(xI) || !tarYI.isIntersectWith(yI) ){
        return;
    }
    treeNode *now=getNode(p);

    if(ans.maxv.val>=now->maxv.val && ans.minv.val<=now->minv.val){
        return;
    }

    if(tarXI.isInclude(xI) && tarYI.isInclude(yI)){
        ans.maxv.val=max(ans.maxv.val, now->maxv.val);
        ans.minv.val=min(ans.minv.val, now->minv.val);
        return;
    }
    query_segtree( son(0), xI.left(), yI.left(), tarXI, tarYI, ans );
    query_segtree( son(1), xI.right(), yI.left(), tarXI, tarYI, ans );
    query_segtree( son(2), xI.left(), yI.right(), tarXI, tarYI, ans );
    query_segtree( son(3), xI.right(), yI.right(), tarXI, tarYI, ans );
}

int main(){
    int T, n, tmp, cas=0;
    scanf("%d", &T);

    while(T--){
        scanf("%d", &n);

        build_segtree(1, Interval(1, n), Interval(1, n));
        int tmp;
        for(int i=1; i<=n; i++){
            for(int j=1; j<=n; j++){
                scanf("%d", &tmp);
                insert_segtree(1, Interval(1, n), Interval(1, n), i, j, tmp);
            }
        }

        int m, x, y, sz;
        scanf("%d", &m);
        printf("Case #%d:\n", ++cas);
        while(m--){
            scanf("%d%d%d", &x, &y, &sz);
            Interval XI, YI;
            XI.l=max(1, x-sz/2), XI.r=min(n, x+sz/2);
            YI.l=max(1, y-sz/2), YI.r=min(n, y+sz/2);

            treeNode ans; ans.reset();

            query_segtree( 1, Interval(1, n), Interval(1, n), XI, YI, ans);

            printf("%d\n", (ans.maxv.val+ans.minv.val)/2);
            insert_segtree(1, Interval(1, n), Interval(1, n), x, y, (ans.maxv.val+ans.minv.val)/2);
        }

    }

    return 0;
}

上面是借鑑的網上的寫法,因爲他將各種都進行了封裝,所以比較好理解。自己感覺競賽還是簡練一點比較好,下面代碼是自己修改的。

#include<bits/stdc++.h>
using namespace std;
const int N=810;
#define son(x) (rt*4-2+x)

struct node{
    int mx, mn;
    void reset(){
        mx=INT_MIN;
        mn=INT_MAX;
    }
}tree[(N<<2)*(N<<2)];

void build(int rt, int xl, int xr, int yl, int yr){
    if(xl>xr || yl>yr) return;
    tree[rt].reset();
    if(xl==xr&&yl==yr)
        return;
    int midx=(xl+xr)>>1, midy=(yl+yr)>>1;
    build(son(0), xl, midx, yl, midy);
    build(son(1), xl, midx, midy+1, yr);
    build(son(2), midx+1, xr, yl, midy);
    build(son(3), midx+1, xr, midy+1, yr);
}
//push_up完全可以放在跟新裏面 寫起來更簡潔
void push_up(int rt, int xl, int xr, int yl, int yr){
    node& now=tree[rt];
    now.reset();
    now.mx=max(now.mx, tree[son(0)].mx);
    now.mn=min(now.mn, tree[son(0)].mn);
    if(yl<yr){
        now.mx=max(now.mx, tree[son(1)].mx);
        now.mn=min(now.mn, tree[son(1)].mn);
    }
    if(xl<xr){
        now.mx=max(now.mx, tree[son(2)].mx);
        now.mn=min(now.mn, tree[son(2)].mn);
    }
    if(xl<xr && yl<yr){
        now.mx=max(now.mx, tree[son(3)].mx);
        now.mn=min(now.mn, tree[son(3)].mn);
    }
}

//point update
void upd(int rt, int xl, int xr, int yl, int yr, int x, int y, int val){
    if(xl>xr || yl>yr) return;

    node& now=tree[rt];
    if(xl==xr&&xl==x && yl==yr&&yl==y){
        now.mx=val;
        now.mn=val;
        return;
    }
    int midx=(xl+xr)>>1, midy=(yl+yr)>>1;

    if(x<=midx && y<=midy){
        upd(son(0), xl, midx, yl, midy, x, y, val);
    }
    else if(x<=midx && y>midy){
        upd(son(1), xl, midx, midy+1, yr, x, y, val);
    }
    else if(x>midx && y<=midy){
        upd(son(2), midx+1, xr, yl, midy, x, y, val);
    }
    else{
        upd(son(3), midx+1, xr, midy+1, yr, x, y, val);
    }

    push_up(rt, xl, xr, yl, yr);
}
//interval query
node query(int rt, int xl, int xr, int yl, int yr, int qxl, int qxr, int qyl, int qyr){
    node tmp; tmp.reset();
    if(xl>xr || yl>yr) return tmp;
    if(xl>qxr || qxl>xr || yl>qyr || qyl>yr) return tmp;
  
    if(qxl<=xl && xr<=qxr && qyl<=yl && yr<=qyr){
        return tree[rt];
    }
    int midx=(xl+xr)>>1, midy=(yl+yr)>>1;
    node ret; ret.reset();
    if(qxl<=midx && qyl<=midy){
        tmp=query(son(0), xl, midx, yl, midy, qxl, qxr, qyl, qyr);
        ret.mx=max(ret.mx, tmp.mx);
        ret.mn=min(ret.mn, tmp.mn);
    }
    if(qxl<=midx && qyr>midy){
        tmp=query(son(1), xl, midx, midy+1, yr, qxl, qxr, qyl, qyr);
        ret.mx=max(ret.mx, tmp.mx);
        ret.mn=min(ret.mn, tmp.mn);
    }
    if(qxr>midx && qyl<=midy){
        tmp=query(son(2), midx+1, xr, yl, midy, qxl, qxr, qyl, qyr);
        ret.mx=max(ret.mx, tmp.mx);
        ret.mn=min(ret.mn, tmp.mn);
    }
    if(qxr>midx && qyr>midy){
        tmp=query(son(3), midx+1, xr, midy+1, yr, qxl, qxr, qyl, qyr);
        ret.mx=max(ret.mx, tmp.mx);
        ret.mn=min(ret.mn, tmp.mn);
    }

    return ret;
}

int main(){

    int T, n, cas=0;
    scanf("%d", &T);
    while(T--){
        scanf("%d", &n);

        build(1, 1, n, 1, n);
        int tmp;
        for(int i=1; i<=n; i++){
            for(int j=1; j<=n; j++){
                scanf("%d", &tmp);
                upd(1, 1, n, 1, n, i, j, tmp);
            }
        }

        int m, x, y, sz;
        scanf("%d", &m);
        printf("Case #%d:\n", ++cas);
        while(m--){
            scanf("%d%d%d", &x, &y, &sz);
            int qxl=max(1, x-sz/2), qxr=min(n, x+sz/2);
            int qyl=max(1, y-sz/2), qyr=min(n, y+sz/2);
            node ans;
           
            ans=query(1, 1, n, 1, n, qxl, qxr, qyl, qyr);
            printf("%d\n", (ans.mn + ans.mx)>>1);
            upd(1, 1, n, 1, n, x, y, (ans.mn+ans.mx)/2);
           
        }
    }

    return 0;
}

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