题目:1270. 数列区间最大值
地址 :https://www.acwing.com/problem/content/submission/1272/
类型:st
题解:
// 线段树解法
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, m, w[N];
// 定义节点。
struct Node {
// 左右两个节点
int l, r;
//节点中的值
int var;
} tr[N * 4];
// 建立线段树 u表示当前节点,l r表示左右两个子节点
void build(int u, int l, int r) {
// 叶子节点时,对其赋值
if (l == r)
tr[u] = {l, r, w[r]};
else {
// 父节点定义,
tr[u] = {l, r};
// 取线段中点 1,2
int mid = l + r >> 1;
// | 表示按位或,<< 表示向箭头的方向移位
// 递归左右两个节点
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
// 父节点最大值定义
tr[u].var = max(tr[u << 1].var, tr[u << 1 | 1].var);
}
}
// 查找最大值
int query(int u, int l, int r) {
// 当u在l和r中,最大值便是
if (tr[u].l >= l && tr[u].r <= r)
return tr[u].var;
// 中间节点
int mid = tr[u].l + tr[u].r >> 1;
int maxv = INT_MIN;
// 遍历左右两个节点
if (l <= mid)
maxv = query(u << 1, l, r);
if (r > mid)
maxv = max(maxv, query(u << 1 | 1, l, r));
// 返回最大值
return maxv;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &w[i]);
build(1, 1, n);
int l, r;
while (m--) {
scanf("%d%d", &l, &r);
printf("%d\n", query(1, l, r));
}
return 0;
}
// st算法
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
const int M = 30;
// M层,每层最多N个
int h[M][N], a[N];
int n, m;
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d%d", &a[i]);
h[0][i] = a[i];
}
// 初始化
for (int i = 1; i <= log2(n); i++) {
// 遍历一遍n
for (int j = 1; j + (1 << i) - 1 <= n; j++) {
// 当前的最大值等于i - i+2^(j+1)-1 与i+2^(j-1) - i+(2^j) -
// 1两个区间
h[i][j] = max(h[i - 1][j], h[i - 1][j + (1 << (i - 1))]);
}
}
int l, r;
while (m--) {
scanf("%d%d", &l, &r);
// 求i
int k = log2(r - l + 1);
printf("%d\n", max(h[k][l], h[k][r - (1 << k) + 1]));
}
return 0;
}