输入样例:
10 2
3 2 4 5 6 8 1 2 9 7
1 4
3 8
输出样例:
5
8
解题思路:
题意为找出任意两区间中的最大值,由于询问的次数是百万级的,可以用线段树存储数列的数据:在树的每个结点中维护区间的左右端点和当前区间的最大值,查找时,通过递归实现 logn 的复杂度。总的时间复杂度为 O(mlogn)。
Java代码:
import java.io.*;
public class Main {
static int []w;
static Node []tree;
static class Node{
int l, r;
int max;
public Node(int l, int r, int max) {
this.l = l;
this.r = r;
this.max = max;//线段的最大值
}
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] split = br.readLine().split(" ");
int n = Integer.parseInt(split[0]);
int m = Integer.parseInt(split[1]);
w = new int[n + 1];
split = br.readLine().split(" ");
for(int i = 1; i <= n; i++)
w[i] = Integer.parseInt(split[i - 1]);
tree = new Node[n * 4];
build(1, 1, n);
StringBuilder ans = new StringBuilder();
for(int i = 0; i < m; i++) {
split = br.readLine().split(" ");
int a = Integer.parseInt(split[0]);
int b = Integer.parseInt(split[1]);
ans.append(query(1, a, b) + "\n");
}
System.out.print(ans);
}
public static void pushUp(int u) {
tree[u].max = Math.max(tree[u << 1].max, tree[u << 1 | 1].max);
}
public static void build(int u, int l, int r) {
if(l == r) tree[u] = new Node(l, r, w[l]);//创建叶子结点,结点中只有一个值时,最大值就是这个值
else {
tree[u] = new Node(l, r, Integer.MIN_VALUE);//非叶子结点,最大值回溯时判断
int mid = l + r >> 1;//划分左右儿子
if(l <= mid) build(u << 1, l, mid);//递归创建左子树
if(r > mid) build(u << 1 | 1, mid + 1, r);
pushUp(u);//回溯,求最大值
}
}
public static int query(int u, int l, int r) {
if(l <= tree[u].l && tree[u].r <= r) return tree[u].max;//结点中线段的区间被查询的区间完全覆盖,直接返回最大值
int mid = tree[u].l + tree[u].r >> 1;//该结点中线段(区间)的中点
int max = Integer.MIN_VALUE;
if(l <= mid) max = Math.max(max, query(u << 1, l, r));//做子树中与带查询区间有交集
if(r > mid) max = Math.max(max, query(u << 1 | 1, l, r));
return max;
}
}