基于简单线段树的RMQ

线段树是擅长处理区间的,是一种类似完美二叉树的数组结构。(完美二叉树是所有叶子深度都相同,并且每个节点要么是叶子节点要么有两个儿子的树)。树上的每个节点都维护一个区间。根维护都是整个区间,每个节点维护的是父亲的区间二等分后的其中一个子区间,对区间对操作可以在O(logn)完成。

const int MAX_N = 1<<17;
int n,dat[2*MAX_N-1];

//初始化
void init(int n_){
    n = 1;
    while(n<n_){
        n*=2;
    }
//将所有对值都设置为INT_MAX
    for(int i=0;i<2*n-1;i++){
       dat[i] = INT_MAX; 
    }
}
//更新第k个元素为a(index 0-n)
void updata(int k,int a){
    k+=n-1;
    dat[k] = a;
    //更新上层元素
    while(k>0){
        k=(k-1)/2;
        dat[k] = min(data[2*k+1],dat[2*k+2]);
    }
}
//求[a,b]的最小值
//k是节点编号,ab是所求区间,lr是对应的(l,r)区间
void query(int a,int b,int k,int l,int r){
    //如果(a,b)不在(l,r)区间内(无交集),返回INF_MAX
    if(a>=r || b<=l){
        return INF_MAX;
    }
    //如果(a,b)包含(l,r),返回当前节点值
    if(a>=l&&b<=r){
        return dat[k];
    }
    //如果有交集,并且(a,b)不包含(l,r),向下递归,返回两个子节点的最小值
    else{
        int vl = query(a,b,k*2+1,l,(l+r)/2);
        int vr = query(a,b,k*2+2,(l+r)/2,r);
        return min(vl,vr);
    }
}

线段树有几个规律:

1、完美二叉树形式的线段树的dat数组长度为 2*n-1;(2n=n+n/2+n/4+....)

2、如果我们要更新第k个元素(k从0开始),则该元素在dat中的下标为k=n-1+k,即更新dat[n-1+k],既然该元素更新了,那么上层也要更新,上层的下标为k=(k-1)/2,dat[k]=min(dat[k*2+1],dat[k*2+2]);(dat[k*2+1]该节点的左子树,dat[k*2+2]该节点的右子树)。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值