线段树【区间修改+单点修改+区间查询+懒标记】

线段树模版代码,代码中有详细注释,这个是区间和以及区间最值维护的综合版本。

实际使用时选择其中部分功能使用即可。另附代码如下:

 

package m5d15;

import java.io.BufferedInputStream;
import java.util.Scanner;
//同时维护区间和以及区间最大值,区间最小值与区间最大值同理
public class 线段树 {
    //封装树节点
    static class Node{
        int l,r;//左右边界
        int lazy;//懒标记
        int sum;//区间和
        int maxt;//最大值
        //调试用的,实际使用时可以删除
        @Override
        public String toString() {
            return "Node{" +
                    "l=" + l +
                    ", r=" + r +
                    ", lazy=" + lazy +
                    ", sum=" + sum +
                    ", maxt=" + maxt +
                    '}';
        }
    }

    static Node[] tree = null;
    static int val[] = null;
    public static void main(String[] args) {
        Scanner sc = new Scanner(new BufferedInputStream(System.in));

        int n = sc.nextInt();
        int m = sc.nextInt();
        val = new int[n+1];
        for(int i=1;i<=n;i++){
            val[i] = sc.nextInt();
        }

        tree = new Node[4*n+1];
        buildTree(1,1,n);

        for(int i=1;i<=m;i++){
            int p = sc.nextInt();
            int l = sc.nextInt();
            int r = sc.nextInt();
            //单点修改
            if(p==1){
                int val = sc.nextInt();
                update(1,l,r,val);
            } else if(p==2) {//求区间和
                System.out.println(query(1,l,r).sum);
            }
            else if(p==3){//求区间最大值
                System.out.println(query(1,l,r).maxt);
            }else{//区间修改
                int val = sc.nextInt();
                update(1,l,r,val);
            }
        }
    }
    //建树
    public static void buildTree(int x,int l,int r){
        tree[x] = new Node();
        tree[x].l = l;
        tree[x].r = r;

        if(l==r) {
            tree[x].sum = val[l];
            tree[x].maxt = val[l];
            return ;
        }
        int mid = (l+r)>>1;
        buildTree(x<<1,l,mid);
        buildTree(x<<1|1,mid+1,r);
        tree[x].sum = tree[x<<1].sum+tree[x<<1|1].sum;
        tree[x].maxt = Math.max(tree[x<<1].maxt,tree[x<<1|1].maxt);
    }
    //单点修改,值加val
    public static void update(int x,int r,int val){
        if(tree[x].l==tree[x].r&&tree[x].r==r){
            tree[x].sum += val;
            tree[x].maxt += val;
            return;
        }
        int mid = (tree[x].l+tree[x].r)>>1;

        if(r<=mid) update(x<<1,r,val);
        else update(x<<1|1,r,val);

        tree[x].sum = tree[x<<1].sum+tree[x<<1|1].sum;
        tree[x].maxt = Math.max(tree[x<<1].maxt,tree[x<<1|1].maxt);
    }
     //下传懒标记
    public static void pushdown(int k){
        //左儿子
        tree[k<<1].lazy+=tree[k].lazy;
        tree[k<<1].sum+=(tree[k<<1].r-tree[k<<1].l+1)*tree[k].lazy;
        tree[k<<1].maxt+=tree[k].lazy;
        //右儿子
        tree[k<<1|1].lazy+=tree[k].lazy;
        tree[k<<1|1].sum+=(tree[k<<1|1].r-tree[k<<1|1].l+1)*tree[k].lazy;
        tree[k<<1|1].maxt+=tree[k].lazy;
        //清除自己的标记
        tree[k].lazy = 0;
    }
    //区间修改,区间内的值全部增加val
    public static void update(int x,int l,int r,int val){
        if(tree[x].l>=l&&tree[x].r<=r){
            //更新值并进行懒标记
            tree[x].sum+=(tree[x].r-tree[x].l+1)*val;
            tree[x].maxt +=val;
            tree[x].lazy +=val;
            return;
        }

        if(tree[x].lazy!=0){
            pushdown(x);
        }

        int mid = (tree[x].r+tree[x].l)>>1;
        if(l<=mid) update(x<<1,l,r,val);
        if(r>mid) update(x<<1|1,l,r,val);

        tree[x].sum = tree[x<<1].sum+tree[x<<1|1].sum;
        tree[x].maxt = Math.max(tree[x<<1].maxt,tree[x<<1|1].maxt);
    }

    //区间查询,查询区间l到r的和以及最大值
    public static Node query(int x,int l,int r){
        if(tree[x].l>=l&&tree[x].r<=r){

            return tree[x];
        }
        if(tree[x].lazy!=0){
            pushdown(x);
        }
        int mid = (tree[x].l+tree[x].r)>>1;
        Node node1=new Node();
        Node node2=new Node();

        if(l<=mid) node1 = query(x<<1,l,r);
        if(r>mid) node2 = query(x<<1|1,l,r);

        Node result = new Node();
        result.sum = node1.sum+node2.sum;
        result.maxt = Math.max(node1.maxt,node2.maxt);

        return result;
    }

}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值