入门RMQ问题 HDU 5289

HDU 5289 :http://acm.hdu.edu.cn/showproblem.php?pid=3874

题目大意: N个数,每一次询问,会给一个区间 [L,R],要求这个区间内的最大数与最小数的差值小于给定的k,问,满足条件的区间数为多少个。有M次询问。

 

使用ST来解决题目中的,最大数和最小数差的RMQ问题。

对于左区间L,若能确定满足情况的最大右区间位置,则以L为左区间的 、 满足题意的区间个数为 R-L+1 个。

所以解题思路为:

     枚举每一个左区间, 二分来判定右区间的位置。累加即可

 

     二分的写法是:

      对于当前的二分区间 [L,R] ,中点为m ,若 [L,M] 的最大值与最小值之差 大于等于k,则区间向左收敛;若满足题意,差值小于k,则向右(回退)收敛。

 

上代码:

 

#include "stdio.h"
#include "cstring"
#include "algorithm"
using namespace std;
#define inf 100009
#define INF 999999999
#define ll long long
#define loop(x,y,z) for(x=y;x<z;x++)
int n;
int mx[inf][20],mi[inf][20];
int a[inf];

void init_d()
{
    memset(mx,0,sizeof mx);
    memset(mi,0,sizeof mi);
    int i,j;
    loop(i,0,n)mx[i][0]=mi[i][0]=a[i];
    for(j=1;(1<<j)<=n;j++)
        for(i=0;i+(1<<j)<=n;i++)
        {
            mx[i][j]=max( mx[i][j-1],mx[i+(1<<(j-1))][j-1] );
            mi[i][j]=min( mi[i][j-1],mi[i+(1<<(j-1))][j-1] );
        }
}
int query(int i,int j)
{
    int k=0;
    while((1<<k)<=j-i+1)k++;
    k--;
    return max( mx[i][k],mx[j-(1<<k)+1][k] )-min( mi[i][k],mi[j-(1<<k)+1][k] );
}
int main()
{
    int i,j,T,k;
    ll ans;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&k);
        loop(i,0,n)scanf("%d",&a[i]);
        init_d();
        ans=0;
        loop(i,0,n)
        {
            int l=i,r=n-1,m;   //二分内容
            while(l<=r)
            {
                m=l+(r-l)/2;
                if(query(i,m)<k)l=m+1;
                else r=m-1;
            }
            ans+=r-i+1;
        }
        printf("%lld\n",ans);
    }

    return 0;
}

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值