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;
}
时间: 2024-10-04 15:07:52

ACM学习历程—HDU4417 Super Mario(树状数组 && 离线)的相关文章

hdu4417 Super Mario 树状数组离线/划分树

http://acm.hdu.edu.cn/showproblem.php?pid=4417 Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2720    Accepted Submission(s): 1322 Problem Description Mario is world-famous plumber

hdu-4417 Super Mario(树状数组 + 划分树)

题目链接: Super Mario Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 32768/32768 K (Java/Others) Problem Description Mario is world-famous plumber. His “burly” figure and amazing jumping ability reminded in our memory. Now the poor princess is

HDU 4417 Super Mario (树状数组/线段树)

Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Description Mario is world-famous plumber. His “burly” figure and amazing jumping ability reminded in our memory. Now the poor princess is in trouble agai

[HDU 4417] Super Mario (树状数组)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4417 题目大意:给你n个数,下标为0到n-1,m个查询,问查询区间[l,r]之间小于等于x的数有多少个. 写的时候逗比了...还是写的太少了.. 我们按照x从小到大排序来查询,然后找区间上的点,如果小于等于它就插入,然后看这个区间内插入了多少个点. 点也是可以排序的.. 详见代码: 1 #include <cstdio> 2 #include <cmath> 3 #include &l

HDU 4417 Super Mario ( 超级马里奥 + 主席树 + 线段树/树状数组离线处理 + 划分树 )

HDU 4417 - Super Mario ( 主席树 + 线段树/树状数组离线处理 + 划分树 ) 这道题有很多种做法,我先学习的是主席树.后面陆续补上线段树离线和划分树 题目大意就是给定一个区间给定一个数列,每次要求你查询区间[L,R]内不超过K的数的数量 主席树做法: 最基本的是静态第k大,这里是求静态的 <= K,差不多,在Query操作里面需要修改修改 先建立size棵主席树,然后询问的时候统计的是 第R棵主席树中[1,K]的数量 - 第L-1棵主席树中[1,K]的数量 注意这里下标

hdu 3333 树状数组+离线处理

http://acm.hdu.edu.cn/showproblem.php?pid=3333 不错的题,想了很久不知道怎么处理,而且答案没看懂,然后找个例子模拟下别人的代码马上懂了---以后看不懂的话就拿个例子模拟下别人的代码 举个例子:1 3 3 5 3 5 查询 a, 2 4 b, 2 5 最初是这么想的:对于a查询,倘若把第二个数第三个数变成1个3,那么到b查询,又出现了两个3,再做处理似乎还是O(n),而且如果先出现2,5查询,后出现2,4查询,那么还需要把删除的数补回来.....o(╯

hdu 4368 树状数组 离线维护

http://acm.hdu.edu.cn/showproblem.php?pid=4638 Problem Description There are n men ,every man has an ID(1..n).their ID is unique. Whose ID is i and i-1 are friends, Whose ID is i and i+1 are friends. These n men stand in line. Now we select an interv

13杭州区域赛现场赛Rabbit Kingdom(树状数组+离线)

题意:给你一个长度数列,再给你m个询问(一个区间),问你在这个区间里面有多少个数与其他的数都互质. 解题思路:你看这种类型的题目都可以肯定这是 离线+树状数组(线段树).主要就是他的更新信息.这里我的处理是先把1-200000(每个数的范围)数里面所有的质因子求出来.然后从后往前遍历数组.会出现以下几种情况 1.a[k]的质因子在后面出现过而[更新标记] 和[被更新标记] 都为假 2.a[k]的质因子在后面出现过的那个位置 I   [更新标记]为 真 . 3.a[k]的质因子在后面出现过且那个位

HDU 3333 Turing Tree 树状数组 离线查询

题意: 给你一个数列,然后有n个查询,问你给定区间中不同数字的和是多少. 思路还是比较难想的,起码对于蒟蒻我来说. 将区间按照先右端点,后左端点从小到大排序之后,对于每个查询,我只要维护每个数字出现的最后一次就可以了(这个结论稍微想一下就可以证明是正确的). 然后就是简单的点更新,区间求和问题了- #include <cstdio> #include <cstring> #include <iostream> #include <map> #include