模板之st表

题意:

给出n个数字与q组询问,每次询问一个区间[l,r]的最小值与最大值。

首先,此题可用线段树保存最大值和最小值。。。但是因为没有修改,所以用一些更简单的数据结构即可

st表的功能:nlogn的时间预处理每个点为端点2^x长度的区间信息,然后就可以在O(1)的时间内完成询问。

mn数组的意义在于保存区间的长度,stmin与stmax来保存最大值与最小值。

每次以i为端点更新左右2^j长度的区间信息,注意先枚举j。

比较以l为左端点与以r为右端点的区间信息,回答询问。

#include<cstdio>
int stmax[100005][20],stmin[100005][20];
int a[100005],mn[100005];
int t,q,n,l,r;
int max(int x,int y)
{
    if(x>y) return x;
    else return y;
}
int min(int x,int y)
{
    if(x<y) return x;
    else return y;
}
int main()
{
    scanf("%d",&n);scanf("%d",&q);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    mn[0]=-1;
    for(int i=1;i<=n;i++)
    {
        if((i&(i-1))==0) mn[i]=mn[i-1]+1;
        else mn[i]=mn[i-1];
        stmax[i][0]=a[i];
        stmin[i][0]=a[i];
    }
    for(int j=1;j<=mn[n];j++)
    {
        for(int i=1;i+(1<<j)<=n+1;i++)
        {
            stmax[i][j]=max(stmax[i][j-1],stmax[i+(1<<j-1)][j-1]);
            stmin[i][j]=min(stmin[i][j-1],stmin[i+(1<<j-1)][j-1]);
        }
    }
    while(q--)
    {
        scanf("%d %d",&l,&r);
        int k=mn[r-l+1];
        printf("%d ",min(stmin[l][k],stmin[r-(1<<k)+1][k]));
        printf("%d
",max(stmax[l][k],stmax[r-(1<<k)+1][k]));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zeroform/p/7787962.html