POJ3264——Balanced Lineup 倍增RMQ裸题

题目链接:
戳我

题目大意:给定一个序列,有q次询问,每次询问给定一个区间,每次询问区间最大减去区间最小。

输入:第一行两个数 n和q;
下面n行,每行一个数,第i+1行,表示序列的第i项;
接下来q行,每行2个数表示询问操作给定的区间。

对于全序列,弄出一个ST表来,然后每次查询都是O1了,很方便,你想用线段树我也不拦你~ 毕竟RMQ这个东西,非常好打…………

但是RMQ也有许多需要注意的地方,今天复习的时候有几个地方没有注意到就被坑了,被坑的地方我会在代码中注释,来提醒一下大家~

代码如下:

#include
#include
#include
#include
using namespace std;
const int size = 100010;
int maxx[size][32],minn[size][32];
int n;
void init()
{
    int k = log2(n);
    for(int j = 1;j <= k;j ++)
    {
        for(int i = 1;i <= n;i ++)
        {
            maxx[i][j] = max(maxx[i][j-1],maxx[i+(1<1)][j-1]);   //左边位运算优先级比较低,不用加括号 
            minn[i][j] = min(minn[i][j-1],minn[i+(1<1)][j-1]);   //这里[]内是[i+(1<<(j-1))],因为这个区间的另一部分是从上一部分末端开始。 
        }
    }
}

int find(int l,int r)
{
    int k = log2(r-l+1);
    int maxans = max(maxx[l][k],maxx[r-(1<1][k]);   //这两个区间可能有重复但是无关紧要,我要求的是最大和最小,就算重复也能求出最大和最小。 
    int minans = min(minn[l][k],minn[r-(1<1][k]);   //同样,这个区间不会超过原区间的范围,因为分别从两个区间下手,考虑的最大化情况也是分别覆盖区间。 
    return (maxans - minans);
}

int main()
{
    memset(minn,60,sizeof(minn));   //预处理不要忘记yoooo我忘了,我检讨………… 
    int q;  scanf("%d%d",&n,&q);
    for(int i = 1;i <= n;i ++)
    {
        scanf("%d",&maxx[i][0]);
        minn[i][0] = maxx[i][0];
    }
    init();
    for(int i = 1;i <= q;i ++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        int ans = find(a,b);
        printf("%d\n",ans);
    }
    return 0;
}

———————————————The End————————————————

你可能感兴趣的:(poj)