【数据结构】线段树

简介

线段树和树状数组这两种数据结构都能处理区间修改、区间查询问题。与树状数组相比线段树有以下特点。
(1)线段树的原理。线段树的原理比树状数组直观,在理论上它比树状数组更好懂,但是线段树的细节很多,应用起来比较烦琐。
(2)线段树的代码。线段树要处理大量细节,代码冗长。一个与线段树有关的题目,基本的线段树那一部分的代码约 40 行,而树状数组的核心代码不到 10 行。
但是线段树比树状数组更通用。很多问题用线段树解决非常直观,线段树比树状数组的应用场合多。做题的时候,如果一道题同时能用线段树和树状数组求解,大多数人会选择用代码多的线段树,而不是代码少的树状数组。因为树状数组的建模、逻辑比线段树的复杂。

例题

在这里插入图片描述

代码

package aaa;

import java.util.Scanner;

public class test_5 {
    static int N = 200001;
    static int[] tree = new int[N << 2];

    public static void main(String[] args) {
        int t = 0, cnt = 0, m, D;
        Scanner scanner = new Scanner(System.in);
        m = scanner.nextInt();
        D = scanner.nextInt();
        update(1, 1, N, 1, N, Integer.MIN_VALUE);
        for (int b = 1; b <= m; b++) {
            String s = scanner.next();
            int x = scanner.nextInt();
            if (s.charAt(0) == 'A') {
                cnt++;
                update(1, 1, N, cnt, cnt, (x + t) % D);
            } else {
                t = query(1, 1, N, cnt - x + 1, cnt);
                System.out.println(t);
            }
        }
    }

    public static int ls(int p) { // 左子节点
        return p << 1;
    }

    public static int rs(int p) { // 右子节点
        return p << 1 + 1;
    }

    public static void pushUp(int p) { // 从下往上传递区间值
        tree[p] = Math.max(tree[ls(p)], tree[rs(p)]);
    }

    public static void build(int p, int pl, int pr) {
        System.out.println(p);
        if (pl == pr) {
            tree[p] = Integer.MIN_VALUE;
            return;
        }
        int mid = (pl + pr) >> 1;
        build(ls(p), pl, mid); //构建左子树
        build(rs(p), mid + 1, pr); //构建右子树
        pushUp(p);
    }

    public static void update(int p, int pl, int pr, int L, int R, int d) {
        if (L <= pl && pr <= R) {
            tree[p] = d;
            return;
        }
        int mid = (pl + pr) >> 1;
        if (L <= mid) {
            update(ls(p), pl, mid, L, R, d);
        }
        if (R > mid) {
            update(rs(p), mid + 1, pr, L, R, d);
        }
        pushUp(p);
    }

    public static int query(int p, int pl, int pr, int L, int R) {
        int res = Integer.MIN_VALUE;
        if (L <= pl & pr <= R) {
            return tree[p];
        }
        int mid = (pl + pr) >> 1;
        if (L <= mid)
            res = Math.max(query(ls(p), pl, mid, L, R), res);
        if (R > mid)
            res = Math.max(res, query(rs(p), mid + 1, pr, L, R));
        return res;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值