hdu5289Assignment

来源:互联网 发布:魔神英雄传 知乎 编辑:程序博客网 时间:2024/06/02 07:16
//给一串序列,找出的区间[l,r]使得在这个区间内的任意两个数的差小于k
//对于第i个数,设一i为右边间得到其左边界的最小值为last[i]
//那么对于以i+1为右边界的区间,其左边界的最小值一定在[last[i],i+1]之间
//用线段树存入区间的最大和最小值
//那么就可以用线段树找出在区间[last[i],i+1]之间与a[i+1]的差值大于等于k且最大的位置
//即为以i+1为右边界的最左边界
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cstdlib>
using namespace std ;
const int maxn = 100010 ;
typedef __int64 ll ;
#define left  v<<1
#define right v<<1|1
int last[maxn] ;
struct Tree
{
    ll ma , mi ;
    int l , r ;
    int v ;
}tree[maxn<<4] ;
ll a[maxn] ;
int n , m , k ;
int ans = -1 ;
void build(int l , int r , int v)
{
    tree[v].l = l ;
    tree[v].r = r;
    if(l == r)
    {
        tree[v].ma = tree[v].mi = a[l] ;
        return ;
    }
    int mid = (l+r)>>1 ;
    build(l , mid , left) ;
    build(mid+1 , r , right) ;
    tree[v].ma = max(tree[left].ma , tree[right].ma) ;
    tree[v].mi = min(tree[left].mi , tree[right].mi) ;
}
void query(int l , int r , int v , ll num)
{
    if(tree[v].l == tree[v].r)
    {
        if(ans == -1 && abs((tree[v].mi - num)) >= k)
        ans = max(ans , tree[v].l) ;
        return ;
    }
    int mid = (tree[v].l + tree[v].r) >> 1 ;
    if(r > mid&&(abs((tree[right].ma - num))>=k||abs((tree[right].mi - num)) >= k))
    query(l,r , right , num) ;
    if(ans == -1 && l<=mid && (abs((tree[left].ma - num))>=k||abs((tree[left].mi - num))>=k))
    query(l,r,left , num) ;
}
int main()
{
    //freopen("in.txt","r" ,stdin) ;
    int T ;
    scanf("%d" , &T) ;
    while(T--)
    {
        scanf("%d%d" ,&n , &k) ;
        for(int i = 1;i <= n;i++)
        scanf("%I64d",&a[i]) ;
        build(1 , n , 1) ;
        ll sum = 1 ;last[1] = 1;
        for(int i = 2;i <= n;i++)
        {
            ans = -1 ;
            query(last[i-1], i , 1 , a[i]) ;
            if(ans == -1)last[i] = last[i-1] ;
            else last[i] = ans + 1;
            sum+=(i-last[i]+1) ;
        }
        printf("%I64d\n" , sum) ;
    }
    return 0 ;
}













0 0