题解:P3865 【模板】ST 表 && RMQ 问题
这是一篇线段树题解。
虽然题目的查询复杂度必须为
前置知识
线段树,模板题传送门。
具体实现
根据题面意思,很容易就可以写出建树,查询的部分。其实和加法的逻辑是一样的。
注意到,这道题目不需要修改数值,所以就没有懒标记、修改函数。最难的懒标记都没有了,剩下的岂不是简简单单。
由于线段树常数较大,且查询复杂度为
inline int read(){
int x = 0, f = 1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
//改动的地方,把 x*10+ch-48 用位运算表示,这样速度会更快一点。
return x * f;
}
代码
于是我们就轻轻松松卡常过了这道题目,下面是代码。
#include <bits/stdc++.h>
#define ld p << 1
#define rd p << 1 | 1
using namespace std;
const int N = 1e5 + 5;
inline int read(){
int x = 0, f = 1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * f;
}
struct Node{
int l, r, zd;
} t[N << 2];
int n, Q, a[N];
void push_up(int p){
t[p].zd = max(t[ld].zd, t[rd].zd);
}
void build(int p, int l, int r){//建树
t[p] = (Node) {l, r, a[l]};
if(l == r) return;
int mid = l + r >> 1;
build(ld, l, mid);
build(rd, mid + 1, r);
push_up(p);
}
int ask(int p, int l, int r){//查询
if(l <= t[p].l && t[p].r <= r){
return t[p].zd;
}
int mid = t[p].l + t[p].r >> 1, ans = -1;
if(l <= mid) ans = max(ans, ask(ld, l, r));
if(r > mid) ans = max(ans, ask(rd, l, r));
return ans;
}
int main(){
n = read(), Q = read();
for(int i = 1;i <= n;i++) a[i] = read();
build(1, 1, n);
while(Q--){
int l = read(), r = read();
printf("%d\n", ask(1, l, r));
}
return 0;
}
不过既然这是 ST 表的模板题,肯定要尊重一下,下面贴一下正解,如何实现可以去看其他题解。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
inline int read(){
int x = 0, f = 1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * f;
}
int n, m, lg[N], f[N][22];
int main(){
n = read(), m = read();
for(int i = 2;i <= n;i++) lg[i] = lg[i / 2] + 1;
for(int i = 1;i <= n;i++){
f[i][0] = read();
}
for(int j = 1;j <= lg[n];j++){
for(int i = 1;i + (1 << j) - 1 <= n;i++){
f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}
}
for(int i = 1;i <= m;i++){
int l = read(), r = read(), lgc, maxl, maxr;
lgc = lg[r - l + 1];
maxl = f[l][lgc], maxr = f[r - (1 << lgc) + 1][lgc];
printf("%d\n", max(maxl, maxr));
}
return 0;
}