“玲珑杯”ACM比赛 Round #19 B.Buildings【二分+RMQ】

1149 - Buildings

Time Limit:2s Memory Limit:128MByte

Submissions:617Solved:159

DESCRIPTION

There are nn buildings lined up, and the height of the ii-th house is hihi.

An inteval [l,r][l,r](lr)(l≤r) is harmonious if and only if max(hl,,hr)min(hl,,hr)kmax(hl,…,hr)−min(hl,…,hr)≤k.

Now you need to calculate the number of harmonious intevals.

INPUT
The first line contains two integers n(1n2×105),k(0k109)n(1≤n≤2×105),k(0≤k≤109).The second line contains nn integers hi(1hi109)hi(1≤hi≤109).
OUTPUT
Print a line of one number which means the answer.
SAMPLE INPUT
3 1
1 2 3
SAMPLE OUTPUT
5
HINT
Harmonious intervals are: [1,1],[2,2],[3,3],[1,2],[2,3][1,1],[2,2],[3,3],[1,2],[2,3].


题目大意:


给你一个长度为N的序列,求有多少个区间,使得区间内最大值-最小值<=k;


思路:


我们知道,如果我们确定了左端点L的话,随着右端点R的增加,会使得最大值越来越大,最小值越来越小,也就是差会越来越大,所以我们这里包含一个单调性。

我们可以O(n)枚举左端点,然后二分右端点然后RMQ预处理能够查询区间的最大值和最小值。

过程维护一个最终位子Pos,那么Pos-L+1就是当前左端点对答案的贡献。


Ac代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cmath>
using namespace std;

int maxsum[250000][30];
int minsum[250000][30];

int a[250000];
int n,k;
void rmq_init()
{
    for(int j = 1; (1<<j) <= n; ++j)
        for(int i = 1; i + (1<<j) - 1 <= n; ++i)
        {
            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 Get_cha(int l, int r)
{
    int k = log2(r-l+1);
    int Max = max(maxsum[l][k], maxsum[r-(1<<k)+1][k]);
    int Min = min(minsum[l][k], minsum[r-(1<<k)+1][k]);
    return Max - Min;
}

int main()
{
    while(~scanf("%d%d",&n,&k))
    {
        for(int i = 1; i <= n;++i)
        {
            scanf("%d",&a[i]);
            maxsum[i][0] = a[i];
             minsum[i][0] = a[i];
        }
        rmq_init();

        long long  ans = 0;
        int l , r;
        for(int i = 1; i <= n; ++i)
        {
            int l=i;
            int r=n;
            int pos=-1;
            while(r-l>=0)
            {
                int mid=(l+r)/2;
                if(Get_cha(i,mid)<=k)
                {
                    pos=mid;
                    l=mid+1;
                }
                else r=mid-1;
            }
            ans += pos - i+1;
        }
        printf("%lld\n",ans);
    }
}













  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值