线段树-快速总结-算法笔记

主要的目的是记录一哈二维线段树,在此之前先简单总结一下一维线段树。

线段树

线段树顾名思义,处理线段(或者称为区间)的整体属性的一种数据结构。
主要操作为-范围更新与查询,时间复杂度为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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值