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
",maxres-minres);
    }
    return 0;
}


原文地址:https://www.cnblogs.com/jzssuanfa/p/6726265.html