ACM学习历程—HDU4417 Super Mario(树状数组 && 离线)

Problem Description

Mario is world-famous plumber. His “burly” figure and amazing jumping ability reminded in our memory. Now the poor princess is in trouble again and Mario needs to save his lover. We regard the road to the boss’s castle as a line (the length is n), on every integer point i there is a brick on height hi. Now the question is how many bricks in [L, R] Mario can hit if the maximal height he can jump is H.

 

 

Input

The first line follows an integer T, the number of test data.
For each test data:
The first line contains two integers n, m (1 <= n <=10^5, 1 <= m <= 10^5), n is the length of the road, m is the number of queries.
Next line contains n integers, the height of each brick, the range is [0, 1000000000].
Next m lines, each line contains three integers L, R,H.( 0 <= L <= R < n 0 <= H <= 1000000000.)

 

 

Output

For each case, output "Case X: " (X is the case number starting from 1) followed by m lines, each line contains an integer. The ith integer is the number of bricks Mario can hit for the ith query.

 

 

Sample Input

1

10 10

0 5 2 7 5 4 3 8 7 7

2 8 6

3 5 0

1 3 1

1 9 4

0 1 0

3 5 5

5 5 1

4 6 3

1 5 7

5 7 3

 

 

Sample Output

Case 1:

4

0

0

3

1

2

0

1

5

1

 

题目大意是求序列中lt到rt范围内比h小的数的个数。

虽然序列是固定的,没有修改操作,但是要想实现在线操作还是很难的。

于是考虑了离线。

首先将所有的查询保存下来。然后按照h从小到大进行排序,当然会纪录下这个查询在原来是第几个。

然后从最小的h开始查,这样的话,就能保证小h查询的满足的元素,大h也是满足的。

于是只需要把序列的元素先去掉,然后从小到大再放回去,查h的时候,保证比h小的元素都回归到序列中。

 

于是操作可以描述为以下几点:

1、 从小到大查询h。

2、 用一个数组,0表示元素还没有回归序列,1表示已经回归序列。

3、 查询h的时候保证比h小的元素都回归序列(首先肯定要对序列中的元素进行排序)

4、 查lt到rt比h小的元素的个数,也就是查询区间内1的个数,也是是区间和。用树状数组维护这段序列。

 

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#define LL long long

using namespace std;

const int maxN = 1e5+5;
int n, m, ans[maxN];

struct Node
{
    int val;
    int id;
}s[maxN];

bool cmpNode(Node x, Node y)
{
    return x.val < y.val;
}

struct Query
{
    int lt, rt;
    int h;
    int id;
}q[maxN];

bool cmpQuery(Query x, Query y)
{
    return x.h < y.h;
}

//树状数组
int d[maxN];

int lowbit(int x)
{
    return x&(-x);
}

void add(int id, int pls)
{
    while(id <= maxN)//id最大是maxN
    {
        d[id] += pls;
        id += lowbit(id);
    }
}

int sum(int to)
{
    int s = 0;
    while(to > 0)
    {
        s = s+d[to];
        to -= lowbit(to);
    }
    return s;
}

int query(int from, int to)
{
    return sum(to)-sum(from-1);
}

void input()
{
    memset(d, 0, sizeof(d));
    memset(s, 0, sizeof(s));
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i)
    {
        scanf("%d", &s[i].val);
        s[i].id = i;
    }
    sort(s+1, s+1+n, cmpNode);
    for (int i = 1; i <= m; ++i)
    {
        scanf("%d%d%d", &q[i].lt, &q[i].rt, &q[i].h);
        q[i].id = i;
    }
    sort(q+1, q+1+m, cmpQuery);
}

void work()
{
    int top = 1;
    for (int i = 1; i <= m; ++i)
    {
        while (top <= n && s[top].val <= q[i].h)
        {
            add(s[top].id, 1);
            top++;
        }
        ans[q[i].id] = query(q[i].lt+1, q[i].rt+1);
    }
}

void output()
{
    for (int i = 1; i <= m; ++i)
        printf("%d\n", ans[i]);
}

int main()
{
    //freopen("test.in", "r", stdin);
    int T;
    scanf("%d", &T);
    for (int times = 1; times <= T; ++times)
    {
        input();
        work();
        printf("Case %d:\n", times);
        output();
    }
    return 0;
}

 

posted on 2015-09-09 16:56  AndyQsmart  阅读(648)  评论(0编辑  收藏  举报

导航