P2880 [USACO07JAN]平衡的阵容Balanced Lineup

传送门

显然是RMQ问题

用ST表就行了

用倍增的思想,像DP一样转移

设 mx[ i ] [ j ] 表示从点 i 开始,后面一共 2^j 个点的最大值

显然 mx[ i ] [ 0 ] = a [ i ](a是原数列)

那么 mx [ i ] [ j ] = max( mx[ i ] [ j-1 ],mx[ i+( 1<<(j-1) ) ] [ j-1 ] )  (前面半段和后面半段取个最值)

预处理是 O(nlogn) 的

for(int i=1;i<=n;i++) mx[i][0]=a[i];//初始值
for(int i=1;(1<<i)<=n;i++)
        for(int j=1;j<=n;j++)
            mx[j][i]=max(mx[j][i-1],mx[j+(1<<(i-1))][i-1]);//更新
预处理

询问是 O(1) 的

找到前面一段区间和后面一段区间(中间有重复覆盖没关系,只要能覆盖到所有点就行)

这样就可以保证覆盖到所有的点了

inline void query(int l,int r)
{
    int k=Log[r-l+1];
    printf("%d
", max(mx[l][k],mx[r-(1<<k)+1][k])-min(mi[l][k],mi[r-(1<<k)+1][k]) );
}
询问

最小值也差不多,就不仔细讲了

最后是完整代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=1e5+7;
int n,m;
int Log[N];
inline void pre_log()//预处理log
{
    Log[1]=0;
    for(int i=2;i<=n;i++)
        Log[i]=Log[i>>1]+1;
}
int a[N];
int mx[N][27],mi[N][27];
inline void query(int l,int r)//询问
{
    int k=Log[r-l+1];
    printf("%d
", max(mx[l][k],mx[r-(1<<k)+1][k])-min(mi[l][k],mi[r-(1<<k)+1][k]) );
}
int main()
{
    int l,r;
    cin>>n>>m;
    pre_log();
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);

    for(int i=1;i<=n;i++) mx[i][0]=mi[i][0]=a[i];//初始值
    for(int i=1;(1<<i)<=n;i++)
        for(int j=1;j<=n;j++)
        {
            mx[j][i]=max(mx[j][i-1],mx[j+(1<<(i-1))][i-1]);
            mi[j][i]=min(mi[j][i-1],mi[j+(1<<(i-1))][i-1]);
        }

    while(m--)
    {
        scanf("%d%d",&l,&r);
        query(l,r);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/LLTYYC/p/9712629.html