HDU5289

题意:求解存在最大差值小于给定K值的所有区间段。

输入:
T(测试数据)
n(数组个数)K(给定区间值的范围)
ai...(数组值)

输出:
ss(所有满足符合条件的区间段)

思路:二分+ST算法,首先利用ST算法初始化数组,找出区间段最大与最小值,然后直接二分查询数组,并判断给定区间最值是否满

足小于K的情况,所以在遍历完一次数组后,可以累加得到符合条件的所有区间和。


#include<stdio.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 100100;


int i,j,n;
int MIN[MAXN][20],MAX[MAXN][20];
int a[MAXN];


void build()//ST构造区间数组最值
{
    for(i=1; i<=n; i++)
        MIN[i][0]=MAX[i][0]=a[i];


    for(i=1; (1<<i)<=n; i++)  //按区间长度递增顺序递推
    {
        int k = i-1;
        for(j=1; j+(1<<i)-1<=n; j++)  //区间起点
        {
            MIN[j][i]=min(MIN[j][k],MIN[j+(1<<k)][k]);
            MAX[j][i]=max(MAX[j][k],MAX[j+(1<<k)][k]);
        }
    }
}
int main()
{
    int T,left,right;
    scanf("%d",&T);
    while(T--)
    {
        int k;
        scanf("%d%d",&n,&k);
        long long ss = 0;
        for(i=1; i<=n; i++)
            scanf("%d",&a[i]);
        build();            //初始化
        int flag = 1;
        for(i=1; i<=n; i++)     //遍历
        {
            left=flag;
            right=i;
            while(left<=right) //二分寻找符合条件的右端点
            {
                int mid=(left+right)/2;
                int x=(int)(log(double(i-mid+1))/log((double)2));
                int MAXX = max(MAX[mid][x],MAX[i-(1<<x)+1][x]);
                int MINN = min(MIN[mid][x],MIN[i-(1<<x)+1][x]);
                if(MAXX-MINN>=k)
                    left=mid+1;
                else
                    right=mid-1;
            }
            flag = left;
            ss+=i-left;
        }


        printf("%lld\n",ss+n);
    }
    return 0;
}


posted @ 2015-07-22 00:57  __夜风  阅读(224)  评论(0编辑  收藏  举报