入门RMQ问题 HDU 5289

来源:互联网 发布:数据库分组查询原理 编辑:程序博客网 时间:2024/06/01 16:55

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;}