题解 P2412 【查单词】

· · 题解

没人用ST表啊,ST表会伤心的~

先讲一下ST表是啥。ST表就是用一个st数组,st[i][j]表示从i开始1<<j个元素的最大值。显然,一段区间的最大值=max(该区间的左半部分,该区间的右半部分),故st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1])

st[i][j-1]就是左半部分,st[i+(1<<(j-1))][j-1]就是右半部分

边界:st[i][0]就是i开始1个元素的最大值。显然,st[i][0]=第i个元素

如何询问最值:见代码注释

代码实现:

/*♂*/
#include<bits/stdc++.h>
using namespace std;
int n,m;
void upr(char &x)//将一个字符变大写 
{
    if ('a'<=x and x<='z') x-=32;
}
string mx(string a,string b)
{
    string x=a,y=b;//开副本 
    for(int i=0;i<a.size();i++) upr(x[i]);
    for(int i=0;i<b.size();i++) upr(y[i]);
    return x>y?a:b;
    //注意这里记得:以x,y为比较标准,但返回原串。
    //我在这里错了很door♂次! 
}
string st[50100][30];
//st数组 
string ask(int l,int r)
{
    int lc=log2(r-l+1);//区间长度求log 
    return mx(st[l][lc],st[r-(1<<lc)+1][lc]);
    //st[l][lc]即为该区间左半部分 
    //st[r-(1<<lc)+1][lc]即为该区间的右半部分 
} 
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        char x[20];
        scanf("%s",x);
        st[i][0]=x;
        //边界条件 
    }
    for(int j=1;(1<<j)<=n;j++)
    //注意:一定要j在外面 
    {
        for(int i=1;i+(1<<(j-1))<=n;i++)
        {
            st[i][j]=mx(st[i][j-1],st[i+(1<<(j-1))][j-1]);
            //转移 
        }
    } 
    while(m--)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        printf("%s\n",ask(l,r).c_str());
    }
    return 0;
}