【ST表】
【ST表】
用于解决区间最值问题(RMQ)
涉及到许多查询区间最小值/最大值问题时->用ST表维护
预处理操作 O(nlogn)
查询操作 O(1)
思想:动态规划+倍增
ST表构建思路
(1)区间dp:dp[l][r]=max(dp[l][x],dp[x+1][r])
(2)二进制优化:对于每个区间长度 都可以分解为2的幂次方之和
(3)空间优化:倍增优化




模版代码
https://www.luogu.com.cn/problem/P3865
struct ST{
vector<vector<int> > f;
vector<int> lg;//预处理取对数向下取整
ST(int n):f(n+1,vector<int>(64)),lg(n+1){
lg[1]=0;
for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
for(int i=1;i<=n;i++) f[i][0]=a[i];
for (int j=1;j<=lg[n];j++)
for (int i=1;i<=n-(1<<j)+1;i++){
f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
//同理,查区间最小值就改成min
}
}
int ask(int x,int y){
int l=lg[y-x+1];
return max(f[x][l],f[y-(1<<l)+1][l]);
}
};
【题目整理】
一起走很长的路!
https://ac.nowcoder.com/acm/contest/95334/E
/*【思路】
本质上是求l到i-1的区间和大于a[i]
转换为前缀和形式:sum[i-1]-sum[l-1]>=a[i]
合并同类项:sum[i-1]-a[i]>=sum[l-1]
->设d[i]=sum[i-1]-a[i]
求d[i]最小值:
如果>=sum[l-1]则完美
如果<sum[l-1] 则答案为sum[l-1]-d[i]最小值
*/
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
typedef pair<int,int> PII;
const int N=200010;
int n,q;
int a[N],s[N],d[N];//注意前缀和的题目:a在1e9的情况下记得开longlong
struct ST{
vector<vector<int> > f;
vector<int> lg;//预处理取对数向下取整
ST(int n):f(n+1,vector<int>(64)),lg(n+1){
lg[1]=0;
for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
for(int i=1;i<=n;i++) f[i][0]=d[i];
for (int j=1;j<=lg[n];j++)
for (int i=1;i<=n-(1<<j)+1;i++){
f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
//同理,查区间最小值就改成min
}
}
int ask(int x,int y){
int l=lg[y-x+1];
return min(f[x][l],f[y-(1<<l)+1][l]);
}
};
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>q;
for(int i=1;i<=n;i++){
cin>>a[i];
s[i]=s[i-1]+a[i];
}
for(int i=1;i<=n;i++) d[i]=s[i-1]-a[i];
ST st(n);
while(q--){
int l,r;
cin>>l>>r;
if(l==r){//记得特判
cout<<"0"<<endl;
continue;
}
int cnt=st.ask(l+1,r)-s[l-1];
if(cnt<0) cout<<-cnt<<endl;
else cout<<"0"<<endl;
}
return 0;
}

浙公网安备 33010602011771号