首页 > 代码库 > NYOJ 119 士兵杀敌(三)(RMQ算法)

NYOJ 119 士兵杀敌(三)(RMQ算法)

采用的的是小牛的写法,蒟蒻第一次写。。

RMQ (Range Minimum/Maximum Query)问题是指:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j里的最小(大)值,也就是说,RMQ问题是指求区间最值的问题。

这里介绍ST算法:采用动态规划的思想:详见

士兵杀敌(三)

时间限制:2000 ms  |  内存限制:65535 KB
难度:5
描述

南将军统率着N个士兵,士兵分别编号为1~N,南将军经常爱拿某一段编号内杀敌数最高的人与杀敌数最低的人进行比较,计算出两个人的杀敌数差值,用这种方法一方面能鼓舞杀敌数高的人,另一方面也算是批评杀敌数低的人,起到了很好的效果。

所以,南将军经常问军师小工第i号士兵到第j号士兵中,杀敌数最高的人与杀敌数最低的人之间军功差值是多少。

现在,请你写一个程序,帮小工回答南将军每次的询问吧。

注意,南将军可能询问很多次。

输入
只有一组测试数据
第一行是两个整数N,Q,其中N表示士兵的总数。Q表示南将军询问的次数。(1<N<=100000,1<Q<=1000000)
随后的一行有N个整数Vi(0<=Vi<100000000),分别表示每个人的杀敌数。
再之后的Q行,每行有两个正正数m,n,表示南将军询问的是第m号士兵到第n号士兵。
输出
对于每次询问,输出第m号士兵到第n号士兵之间所有士兵杀敌数的最大值与最小值的差。
样例输入
5 2
1 2 6 9 3
1 2
2 4
样例输出
1
7

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<limits.h>
#include<cmath>
typedef long long LL;
using namespace std;
#define REPF( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define CLEAR( a , x ) memset ( a , x , sizeof a )
const int maxn=100010;
int maxsum[maxn][20],minsum[maxn][20];//从第i个起连续2^k
int n,m;
int l,r;
void RMQ(int n)
{
    for(int j=1;j<=20;j++)
    {
        for(int i=1;i<=n;i++)
        {
            if(i+(1<<j)-1<=n)
            {
                maxsum[i][j]=max(maxsum[i][j-1],maxsum[i+(1<<(j-1))][j-1]);
                minsum[i][j]=min(minsum[i][j-1],minsum[i+(1<<(j-1))][j-1]);
            }
        }
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&maxsum[i][0]);
        minsum[i][0]=maxsum[i][0];
    }
    RMQ(n);
    while(m--)
    {
        scanf("%d%d",&l,&r);
        int k=(int)(log(r-l+1.0)/log(2.0));
        int maxres=max(maxsum[l][k],maxsum[r-(1<<k)+1][k]);//注意
        int minres=min(minsum[l][k],minsum[r-(1<<k)+1][k]);
        printf("%d\n",maxres-minres);
    }
    return 0;
}


NYOJ 119 士兵杀敌(三)(RMQ算法)