ACM学习历程—HDU 5289 Assignment(线段树)

Problem Description

Tom owns a company and he is the boss. There are n staffs which are numbered from 1 to n in this company, and every staff has a ability. Now, Tom is going to assign a special task to some staffs who were in the same group. In a group, the difference of the ability of any two staff is less than k, and their numbers are continuous. Tom want to know the number of groups like this.

Input

In the first line a number T indicates the number of test cases. Then
for each case the first line contain 2 numbers n, k
(1<=n<=100000, 0<k<=10^9),indicate the company has n
persons, k means the maximum difference between abilities of staff in a
group is less than k. The second line contains n
integers:a[1],a[2],…,a[n](0<=a[i]<=10^9),indicate the i-th staff’s
ability.

Output

For each test,output the number of groups.

Sample Input

2
4 2
3 1 2 4
10 5
0 3 4 5 2 1 6 7 8 9

Sample Output

5
28

Hint

First Sample, the satisfied groups include:[1,1]、[2,2]、[3,3]、[4,4] 、[2,3]

题目大意是求满足下列条件的子区间的个数:

对于子区间[L, R]内的任意两个元素的差值小于k。

首先可以肯定的是,以An起始的区间肯定是[n, n]。

然后以An-1起始的区间最长是[n-1, n],然后考虑需不需要把区间的右值减小,也就是考虑An和An-1的差值是否小于k。假设最终的区间为[n-1, d(n-1)]。

于是对于以An-2起始的区间,自然最长是[n-2, d(n-1)],然后考虑需不需要把区间的右值减小,也就是考虑这个区间内是否存在某个值与An-2的差值大于等于k。

以此类推,以Ai起始的区间应为[i, min(d(i+1), p)],其中p是i右侧最后一个满足与Ai差值小于k的数的脚标。

于是采用线段树记录区间的最大值和最小值,就能查询出任意[i, n]区间里第一个满足与Ai差值大于等于k的值的位置x,然后x-1即为最后一个满足与Ai差值小于k的数的脚标。

(此处采用ans记录x,ans为-1表示没找到,自然x-1就是n)

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <algorithm>
#define LL long long

using namespace std;

int n, k;
int a[100005], ans;
int d[100005];

//线段树
//区间每点增值,求区间和
const int maxn = 100005;
struct node
{
    int lt, rt;
    LL mi, ma;
}tree[4*maxn];

//向上更新
void pushUp(int id)
{
    tree[id].mi = min(tree[id<<1].mi, tree[id<<1|1].mi);
    tree[id].ma = max(tree[id<<1].ma, tree[id<<1|1].ma);
}

//建立线段树
void build(int lt, int rt, int id)
{
    tree[id].lt = lt;
    tree[id].rt = rt;
    tree[id].mi = 0;//每段的初值,根据题目要求
    tree[id].ma = 0;
    if (lt == rt)
    {
        tree[id].mi = tree[id].ma = a[lt];
        return;
    }
    int mid = (lt + rt) >> 1;
    build(lt, mid, id<<1);
    build(mid+1, rt, id<<1|1);
    pushUp(id);
}

void query(int lt, int rt, int id, int v)
{
    if (tree[id].lt == tree[id].rt)
    {

        if (abs(tree[id].mi-v) >= k)
        {
            if (ans == -1 || ans > tree[id].lt)
                ans = tree[id].lt;
        }
        return;
    }
    int mid = (tree[id].lt + tree[id].rt) >> 1;
    if (lt <= mid)
        if (abs(tree[id<<1].mi-v) >= k || abs(tree[id<<1].ma-v) >= k)
            query(lt, rt, id<<1, v);
    if (ans == -1 && rt > mid)
        if (abs(tree[id<<1|1].mi-v) >= k || abs(tree[id<<1|1].ma-v) >= k)
            query(lt, rt, id<<1|1, v);
}

void input()
{
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; ++i)
    {
        scanf("%d", &a[i]);
    }
    build(1, n, 1);
}

void work()
{
    LL sum = 1;
    d[n] = n;
    for (int i = n-1; i >= 1; --i)
    {
        ans = -1;
        query(i, n, 1, a[i]);
        if (ans != -1)
            ans -= 1;
        else
            ans = n;

        d[i] = min(ans, d[i+1]);
        sum += d[i]-i+1;
    }
    printf("%lld\n", sum);
}

int main()
{
    //freopen("test.txt", "r", stdin);
    int T;
    scanf("%d", &T);
    for (int times = 0; times < T; ++times)
    {
        input();
        work();
    }
    return 0;
}
时间: 2024-10-22 06:30:18

ACM学习历程—HDU 5289 Assignment(线段树)的相关文章

ACM学习历程—HDU 2795 Billboard(线段树)

Description At the entrance to the university, there is a huge rectangular billboard of size h*w (h is its height and w is its width). The board is the place where all possible announcements are posted: nearest programming competitions, changes in th

ACM学习历程—HDU 5023 A Corrupt Mayor&#39;s Performance Art(广州赛区网赛)(线段树)

Problem Description Corrupt governors always find ways to get dirty money. Paint something, then sell the worthless painting at a high price to someone who wants to bribe him/her on an auction, this seemed a safe way for mayor X to make money. Becaus

ACM学习历程—HDU 4726 Kia&#39;s Calculation( 贪心&amp;&amp;计数排序)

DescriptionDoctor Ghee is teaching Kia how to calculate the sum of two integers. But Kia is so careless and alway forget to carry a number when the sum of two digits exceeds 9. For example, when she calculates 4567+5789, she will get 9246, and for 12

hdu 5289 关于线段树的解法 很有意思

欢迎参加--BestCoder周年纪念赛(高质量题目+多重奖励) Assignment Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 1565    Accepted Submission(s): 754 Problem Description Tom owns a company and he is the boss. There

HDU 5289 思路+线段树处理

给出N个数,和K 求这N个数的所有满足条件(最大数-最小数<k)的区间个数 数组b记录以当前位置开始,到最右端最多满足条件的数的个数,b数组的值可通过二分+线段树查找区间最大最小值得到 对于第二组数据 10 5 0 3 4 5 2 1 6 7 8 9 B数组为 3 7 7 7 3 1 4 3 2 1 由于当前I点取最右端值可能会导致i+1点和后面取到的点不满足条件,所有应有:b[i]<=b[i+1]+1 得B数组 3 5 4 3 2 1 4 3 2 1 ans=28 #include &quo

ACM学习历程—HDU 5536 Chip Factory(xor &amp;&amp; 字典树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5536 题目大意是给了一个序列,求(si+sj)^sk的最大值. 首先n有1000,暴力理论上是不行的. 此外题目中说大数据只有10组,小数据最多n只有100.(那么c*n^2的复杂度应该差不多) 于是可以考虑枚举i和j,然后匹配k. 于是可以先把所有s[k]全部存进一个字典树, 然后枚举s[i]和s[j],由于i.j.k互不相等,于是先从字典树里面删掉s[i]和s[j],然后对s[i]+s[j]这个

ACM学习历程—HDU 4287 Intelligent IME(字典树 || map)

Description We all use cell phone today. And we must be familiar with the intelligent English input method on the cell phone. To be specific, the number buttons may correspond to some English letters respectively, as shown below: 2 : a, b, c    3 : d

ACM学习历程—HDU 5534 Partial Tree(动态规划)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5534 题目大意是给了n个结点,让后让构成一个树,假设每个节点的度为r1, r2, ...rn,求f(x1)+f(x2)+...+f(xn)的最大值. 首先由于是树,所以有n-1条边,然后每条边连接两个节点,所以总的度数应该为2(n-1). 此外每个结点至少应该有一个度. 所以r1+r2+...rn = 2n-2.ri >= 1; 首先想到让ri >= 1这个条件消失: 令xi = ri,则x1+x

ACM学习历程—HDU 3915 Game(Nim博弈 &amp;&amp; xor高斯消元)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3915 题目大意是给了n个堆,然后去掉一些堆,使得先手变成必败局势. 首先这是个Nim博弈,必败局势是所有xor和为0. 那么自然变成了n个数里面取出一些数,使得xor和为0,求取法数. 首先由xor高斯消元得到一组向量基,但是这些向量基是无法表示0的. 所以要表示0,必须有若干0来表示,所以n-row就是消元结束后0的个数,那么2^(n-row)就是能组成0的种数. 对n==row特判一下. 代码: