洛谷P3372 线段树模板1 Java

原题链接

import java.io.*;
class Node {
    int l; // 区间左端点
    int r; // 区间右端点
    long sum; // 区间和
    long lazy; // 懒惰标记

    public Node(int l, int r, long sum, long lazy) {
        this.l = l;
        this.r = r;
        this.sum = sum;
        this.lazy = lazy;
    }
}

/**
 * @author wangshaoyu
 */
public class P3372 {

    static int n; // 数据范围 [1, n]
    static int[] array; // 原始数组
    static Node[] tree; // 线段树

    // 线段数树初始化
    static void init() {
        tree = new Node[n * 4];
        for (int i = 1; i < tree.length; i++) {
            tree[i] = new Node(0, 0, 0, 0);
        }
    }

    // 建树,用回溯从下往上建
    static void build(int l, int r, int num) {
        tree[num].l = l;
        tree[num].r = r;
        // 如果区间长度为 1,递归结点
        if (l == r) {
            tree[num].sum = array[l];
            return;
        }
        int mid = (l + r) / 2;
        build(l, mid, num * 2);
        build(mid + 1, r, num * 2 + 1);
        update(num); // 记得更新结点的值
    }

    // 更新结点的值
    static void update(int num) {
        tree[num].sum = tree[num * 2].sum + tree[num * 2 + 1].sum;
    }

    // 区间修改,区间类型有三种情况
    // 将区间[l, r]每个都加上 value
    static void modifySegment(int l, int r, int num, int value) {
        // 如果找到要修改的区间
        if (tree[num].l == l && tree[num].r == r) {
            // 这个结点的值确实是这个结点的值,但是它的子结点的值是还没修改的,因此查询的时候需要先修改子结点的值
            tree[num].lazy += value;
            tree[num].sum += (r - l + 1) * value; // 添加懒惰标记,暂时不需要给儿子结点修改值
            return;
        }

        // 注意:修改区间也要 pushDown
        if (tree[num].lazy != 0) {
            pushDown(num);
        }

        int mid = (tree[num].l + tree[num].r) / 2;
        // 修改的区间都包含在左子树里
        if (r <= mid) {
            modifySegment(l, r, num * 2, value);
        }
        // 修改的区间都包含在右子树里
        else if (l > mid) {
            modifySegment(l, r, num * 2 + 1, value);
        }
        // 将要修改的区间拆开
        else {
            modifySegment(l, mid, num * 2, value);
            modifySegment(mid + 1, r, num * 2 + 1, value);
        }
        update(num);
    }

    // 用于将懒惰标记下传给儿子们,然后更新儿子们的值,清空当前结点的懒惰标记
    // 当前结点的懒惰标记是对儿子结点的值起作用的,对自己是无关的
    static void pushDown(int num) {
        // 如果是叶子结点
        if (tree[num].l == tree[num].r) {
            tree[num].lazy = 0;
            return;
        }
        tree[num * 2].lazy += tree[num].lazy;
        tree[num * 2 + 1].lazy += tree[num].lazy;

        tree[num * 2].sum += (tree[num * 2].r - tree[num * 2].l + 1) * tree[num].lazy;
        tree[num * 2 + 1].sum += (tree[num * 2 + 1].r - tree[num * 2 + 1].l + 1) * tree[num].lazy;

        tree[num].lazy = 0;
    }

    // 区间查询
    static long query(int l, int r, int num) {
        if (tree[num].lazy != 0) {
            pushDown(num);
        }
        if (tree[num].l == l && tree[num].r == r) {
            return tree[num].sum;
        }
        int mid = (tree[num].l + tree[num].r) / 2;
        if (r <= mid) {
            return query(l, r, num * 2);
        }
        if (l > mid) {
            return query(l, r, num * 2 + 1);
        }
        return query(l, mid, num * 2) + query(mid + 1, r, num * 2 + 1);
    }

    public static void main(String[] args) throws IOException {

        n = nextInt();
        int m = nextInt(); // 总操作个数
        array = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            array[i] = nextInt();
        }

        // 开始建树
        init();
        build(1, n, 1);
        // 开始查询
        for (int i = 0; i < m; i++) {
            int oper = nextInt();
            int x = nextInt();
            int y = nextInt();
            if (oper == 1) {
                int k = nextInt();
                modifySegment(x, y, 1, k);
                
// 				  测试数据
//                System.out.println("******************");
//                for (int j = 1; j <= 7; j++) {
//                    System.out.println(tree[j].l + " " + tree[j].r + " " + tree[j].sum + " " + tree[j].lazy);
//                }
//                System.out.println("*******************");

            }
            else {
                long ans = query(x, y, 1);
                pw.println(ans);
            }
        }
        pw.flush();
    }

    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StreamTokenizer st = new StreamTokenizer(br);
    static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
    static int nextInt() throws IOException {
        st.nextToken();
        return (int) st.nval;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值