ST表模板(维护区间最大值)

众所周知,ST表可以用来维护任意一段区间的最大最小值。ST表的状态可以描述为从i开始区间长度为2^j的区间。因此核心代码为

for(int j = 0; j< log(n);j++)
    for(int i = 0 ; i< n;i++)
        f[i][j] = min(f[i][j-1], f[i+2^j][j-1];
// 模板:(维护区间最大值的ST表)
#include<iostream>
using namespace std;
int ST[5005][5005] ,pre[5005],pre2[5005];
int a[5005];
int n;


void makeST()
{
  pre[0]=1;for(int i=1;i<=20;i++) pre[i]=pre[i-1]<<1;
  pre2[0]=-1;for(int i=1;i<=n;i++) pre2[i]=pre2[i>>1]+1;
  for(int i=1;i<=n;i++) ST[i][0]=i;
  for(int j=1;j<=20;j++)
    for(int i=1;i<=n;i++){
      if(i+pre[j]-1<=n){
       int x1=ST[i][j-1],x2=ST[i+pre[j-1]][j-1];
       if(a[x1]>a[x2]) ST[i][j]=x1;
       else ST[i][j]=x2;
      }
    }
}
int query(int l,int r)
{
  if(l==r)return l;
  int x=pre2[r-l+1];
  int x1=ST[l][x],x2=ST[r-pre[x]+1][x];
  return a[x1]>a[x2]?x1:x2;
}
int main()
{
    cin>>n;
    for(int i = 0; i< n; i++)
    {
        cin>>a[i]; 
    }   
    makeST();
    int x,y;
    while(cin>>x>>y)
    cout<<"max index is "<<query(x,y)<<endl<<"max value is "<<a[query(x,y)]<<endl;
    return 0;
} 
在解决以某个值为最小(最大)值的最大区间问题时,单调栈是一种非常有效的数据结构。其核心思想是通过维护一个单调递增或递减的栈来高效地找到每个元素作为最值时所能覆盖的最大区间。 对于求解区间最大值的问题,通常采用**单调递减栈**来处理。每当遇到一个比当前栈顶元素大的值时,就将栈中所有小于该值的元素弹出,这样可以确定这些被弹出元素所能构成的以它们为最大值的最大区间。同时,新进来的元素也会被压入栈中,继续维护栈的单调性。 下面给出一个经典的单调栈算法模板,用于计算每个元素作为最大值时所能扩展到的最远左右边界: ```cpp #include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 5; int a[maxn], L[maxn], R[maxn]; // L[i] 示a[i]左边第一个大于它的位置,R[i]同理 stack<int> st; void computeBoundaries(int n) { // 求解左边界 for (int i = 1; i <= n; ++i) { while (!st.empty() && a[st.top()] <= a[i]) { st.pop(); } if (st.empty()) { L[i] = 0; } else { L[i] = st.top(); } st.push(i); } // 清空栈,准备求右边界 while (!st.empty()) st.pop(); // 求解右边界 for (int i = n; i >= 1; --i) { while (!st.empty() && a[st.top()] <= a[i]) { st.pop(); } if (st.empty()) { R[i] = n + 1; } else { R[i] = st.top(); } st.push(i); } } ``` 在这个模板中: - `L[i]` 存储的是数组中第 `i` 个元素左侧第一个比它大的元素的位置; - `R[i]` 存储的是右侧第一个比它大的元素的位置; - 这样就可以计算出以 `a[i]` 为最大值的最大区间长度为 `(R[i] - L[i] - 1)`。 此方法的时间复杂度为 O(n),空间复杂度也为 O(n),适用于大规模数据的处理[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值