线段树实战

一 问题描述

二 输入

10
5 3 7 2 12 1 6 4 8 15
1 10
7 20
1 10

三 代码

package com.platform.modules.alg.alglib.p78;

public class P78 {
    public String output = "";

    private final int maxn = 100005;
    private final int inf = 0x3f3f3f3f;
    private int n;
    private int a[] = new int[maxn];
    private node tree[] = new node[maxn * 4]; //树结点存储数组

    public P78() {
        for (int i = 0; i < tree.length; i++) {
            tree[i] = new node();
        }
    }

    // 创建线段树,k 表示存储下标,区间 [l,r]
    void build(int k, int l, int r) {
        tree[k].l = l;
        tree[k].r = r;
        if (l == r) {
            tree[k].mx = a[l];
            return;
        }
        int mid, lc, rc;
        mid = (l + r) / 2; // 划分点
        lc = k * 2; // 左孩子存储下标
        rc = k * 2 + 1; // 右孩子存储下标
        build(lc, l, mid);
        build(rc, mid + 1, r);
        tree[k].mx = Math.max(tree[lc].mx, tree[rc].mx); // 结点的最大值等于左右孩子最值的最大值
    }

    // 将 a[i]修改更新为 v
    void update(int k, int i, int v) {
        if (tree[k].l == tree[k].r && tree[k].l == i) // 找到a[i]
        {
            tree[k].mx = v;
            return;
        }
        int mid, lc, rc;
        mid = (tree[k].l + tree[k].r) / 2; // 划分点
        lc = k * 2; // 左孩子存储下标
        rc = k * 2 + 1; // 右孩子存储下标
        if (i <= mid)
            update(lc, i, v); // 到左子树修改更新
        else
            update(rc, i, v); // 到右子树修改更新
        tree[k].mx = Math.max(tree[lc].mx, tree[rc].mx); // 返回时修改更新最值
    }

    int query(int k, int l, int r) // 求区间[l..r]的最值
    {
        if (tree[k].l >= l && tree[k].r <= r) // 找到该区间
            return tree[k].mx;
        int mid, lc, rc;
        mid = (tree[k].l + tree[k].r) / 2; // 划分点
        lc = k * 2; // 左孩子存储下标
        rc = k * 2 + 1; // 右孩子存储下标
        int Max = -inf;
        if (l <= mid)
            Max = Math.max(Max, query(lc, l, r)); // 到左子树查询
        if (r > mid)
            Max = Math.max(Max, query(rc, l, r)); // 到右子树查询
        return Max;
    }

    void print(int k) {
        if (tree[k].mx != 0) {
            output += k + "\t" + tree[k].l + "\t" + tree[k].r + "\t" + tree[k].mx + "\t" + "\n";
            print(k << 1); // 左孩子
            print((k << 1) + 1); // 右孩子
        }
    }

    public String cal(String input) {
        int l, r;
        int i, v;
        String[] line = input.split("\n");
        n = Integer.parseInt(line[0]); // 10
        String[] nums = line[1].split(" ");

        // 5 3 7 2 12 1 6 4 8 15
        for (i = 1; i <= n; i++)
            a[i] = Integer.parseInt(nums[i - 1]);
        build(1, 1, n); // 创建线段树
        print(1);
        // 输入查询最值的区间 [l,r] 1 10
        String[] range = line[2].split(" ");
        l = Integer.parseInt(range[0]);
        r = Integer.parseInt(range[1]);
        // 求区间[l..r]的最值
        output += query(1, l, r) + "\n";
        // 输入修改元素的下标和值 i v 7 20
        String[] change = line[3].split(" ");
        i = Integer.parseInt(change[0]);
        v = Integer.parseInt(change[1]);
        update(1, i, v); // 将 a[i] 修改更新为 v
        // 求区间[l..r]的最值 1 10
        range = line[4].split(" ");
        l = Integer.parseInt(range[0]);
        r = Integer.parseInt(range[1]);
        // 求区间 [l..r] 的最值
        output += query(1, l, r) + "\n";
        return output;
    }
}

// 结点
class node {
    int l; // l 表示区间左右端点
    int r; // r 表示区间左右端点
    int mx; // mx表示区间[l,r]的最值
}

四 测试

1    1    10    15    
2    1    5    12    
4    1    3    7    
8    1    2    5    
16    1    1    5    
17    2    2    3    
9    3    3    7    
5    4    5    12    
10    4    4    2    
11    5    5    12    
3    6    10    15    
6    6    8    6    
12    6    7    6    
24    6    6    1    
25    7    7    6    
13    8    8    4    
7    9    10    15    
14    9    9    8    
15    10    10    15    
15
20

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值