一 问题描述
![](https://i-blog.csdnimg.cn/blog_migrate/200f08d7e58de5fc16d81b9a0c775a43.png)
![](https://i-blog.csdnimg.cn/blog_migrate/701b6e79d0b2d9ecaed880a7550a5228.png)
二 输入
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