RMQ 线段树 区间和、区间最值 代码

这个博客主要介绍了如何使用线段树数据结构来实现区间内的最小值查询和求和操作。代码中展示了创建线段树的两种方法:`buildMin`用于构建求最小值的线段树,`buildSum`用于构建求和的线段树。同时提供了`query`方法进行区间查询,以及`updateForOne`和`updateForOneSum`方法进行单点的更新操作。这些方法利用了分治策略,将问题分解到子节点,并通过递归进行处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

public class SegmentTree {

    @Test
    public void test(){
        buildMin(0);
        int min = query(0, 3, 5);
        System.out.println(min);
//        updateOne(0,4,5);
//        max = query(0, 3, 5);
//        System.out.println(max);buildSum(0);

    }

    /**创建线段树(求和)
    */
    int[] data = {5, 9, 7, 4, 6, 1};//数据
    SegNode[] nodes = new SegNode[data.length << 2];
    private void buildSum(int index){
        SegNode node = nodes[index];//取出节点
        if(node == null){//根节点
            nodes[index] = new SegNode(0,data.length-1);
            node = nodes[index];
        }
        if (node.start == node.end){//叶节点
            node.val = data[node.start];
        }else {
            int mid = (node.start + node.end) >> 1;
            int left = (index << 1) + 1;
            int right = left+1;
            nodes[left] = new SegNode(node.start,mid);//左子树
            nodes[right] = new SegNode(mid+1,node.end);//右子树
            buildSum(left);//递归
            buildSum(right);
            node.val = nodes[left].val + nodes[right].val;//求和
        }
    }

    /**
     * 创建线段树(最小值)
     */
    private void buildMin(int index){
        SegNode node = nodes[index];//取出节点
        if(node == null){//根节点
            nodes[index] = new SegNode(0,data.length-1);
            node = nodes[index];
        }
        if (node.start == node.end){//叶节点
            node.val = data[node.start];
        }else{
            int mid = (node.start + node.end) >> 1;
            int left = (index << 1) + 1;
            int right = left+1;
            nodes[left] = new SegNode(node.start,mid);//左子树
            nodes[right] = new SegNode(mid+1,node.end);//右子树
            buildMin(left);//递归
            buildMin(right);
            node.val = Math.min(nodes[left].val, nodes[right].val);//最小值
        }
    }

    /**
     * 区间查找
     * @param index 起始索引下标
     * @param start 区间左端点
     * @param end 区间右端点
     * @return 查找结构
     */
    private int query(int index,int start,int end){
        SegNode node = nodes[index];//取出来
        if(start <= node.start && node.end <= end)//如果在节点在查找区间内
            return node.val;
        if (start > node.end || node.end < node.start){//区间之外
            return Integer.MAX_VALUE;//没找到
        }else{//部分在区间内
            return Math.min(query((index << 1)+1,start,end),query((index << 1)+2,start,end));//最小值
//            return query((index << 1)+1,start,end) + query((index << 1)+2,start,end);//求和
        }
    }
    /**
     * 区间求和查找
     * @param index 起始索引下标
     * @param start 区间左端点
     * @param end 区间右端点
     * @return 查找求和结果
     */
    private int querySum(int index,int start,int end){
        SegNode node = nodes[index];//取出来
        if(start == node.start && node.end == end)//如果在节点在查找区间内
            return node.val;
        if (start > node.end || node.end < node.start){//区间之外
            return 0;//没找到
        }else{//部分在区间内
            int mid = (node.start + node.end) >> 1;
            return query((index << 1) + 1,start,mid < end ? mid : end) + query((index << 1) + 2,mid + 1 > start ? (mid+1) : start,end);//求和
        }
    }

    /**
     * 求和,修改单点
     * @param index
     * @param updateIndex
     * @param val
     * @return 区间单点修改,求和
     */
    private int updateForOneSum(int index,int updateIndex,int val){
        SegNode node = nodes[index];
        int remain;
        if(node.start == node.end && node.start == updateIndex){
            remain = val - node.val;
            node.val = val;
            return remain;
        }else{
            int mid = (node.start + node.end) >> 1;
            if(updateIndex <= mid){
                remain = updateForOneSum((index << 1) + 1,updateIndex,val);
            }else{
                remain = updateForOneSum((index << 1) + 2,updateIndex,val);
            }
        }
        node.val += remain;
        return remain;
    }

    /**
     * 最值,修改单点
     * @param index
     * @param updateIndex
     * @param val
     * @return 区间单点修改,最值
     */
    private void updateForOne(int index,int updateIndex,int val){
        SegNode node = nodes[index];
        if(node.start == node.end && node.start == updateIndex){
            node.val = val;
        }else{
            int mid = (node.start + node.end) >> 1;
            int left = (index << 1) + 1;
            int right = left + 1;
            if(updateIndex <= mid){
                updateForOneSum(left,updateIndex,val);
            }else{
                updateForOneSum(right,updateIndex,val);
            }
            node.val = Math.min(nodes[left].val,nodes[right].val);
        }
    }



    /**
     * 线段树的数据结构
     */
    class SegNode{
        int start;
        int end;
        int val;
        public SegNode(int s,int e){
            start = s;
            end = e;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值