Super Mario(主席树)

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.

题目链接

  • 题意是马里奥路经1到n,每一个整数点上都有一块砖,每一块砖都有自己的高度h[i],下面有q个询问:l,r,h,问,在[l,r],马里奥能跳h这么高,一共能顶到多少块砖。
  • 很容易看出来是主席树,用主席树查一下小于等于这个高度的砖块在这个区间有多少个就好了。主席树区间查询,要注意的就是别忘了初始化,最后查询的时候判断一下这个区间位置是不是0,如果是0直接就不用查了,要不然会TLE
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e5+5;
int cnt, n, m, x, y, k;
int root[maxn], a[maxn];
struct node
{
    int l, r, sum;  //sum is value for this segment
}T[maxn*20];
vector<int> v;

inline int Get_Id(int x)
{
    return lower_bound(v.begin(), v.end(), x)-v.begin()+1;
}

void update(int l, int r, int &x, int y, int pos)
{
    //x is current tree, and y is the previous tree. At the begining, the current one is initializated by the previous one
    T[++cnt] = T[y];    T[cnt].sum++;   x = cnt;    //return x as the node's id of the root of current tree
    if(l == r)  return ;
    int mid = (l+r)>>1;
    if(mid >= pos)  update(l, mid, T[x].l, T[y].l, pos);
    else update(mid+1, r, T[x].r, T[y].r, pos);
}

int query(int l, int r, int x, int y, int left, int right)
{
    //cout << "(left, right): (" << left << ", " << right << "), (l, r): (" << l << ", " << r << ")" << endl;
    if(left <= l && r <= right) return (T[y].sum-T[x].sum);
    int mid = (l+r)>>1;
    /*Amazing! You can't write your code like as follows:
    int result = 0;
    if(left <= mid) result += query(l, mid, T[x].l, T[y].l, left, right);
    if(right > mid) result += query(mid+1, r, T[x].r, T[y].r, left, right);
    , or your code will mle*/
    if(right <= mid) return query(l, mid, T[x].l, T[y].l, left, right);
    else if(left > mid) return query(mid+1, r, T[x].r, T[y].r, left, right);
    else return query(l, mid, T[x].l, T[y].l, left, right)+query(mid+1, r, T[x].r, T[y].r, left, right);
}

int main()
{
    int T;
    cin >> T;
    for(int cas = 1; cas <= T; cas++)
    {
        //initialization
        memset(root, 0, sizeof(root));
        cnt = 0;
        v.clear();
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++) scanf("%d", &a[i]), v.push_back(a[i]);  //array v is used for discretization
        printf("Case %d:\n", cas);
        //discretizate
        sort(v.begin(), v.end());
        v.erase(unique(v.begin(), v.end()), v.end());
        int Max_Size = v.size();
        //end of discretizate
        for(int i = 1; i <= n; i++) update(1, Max_Size, root[i], root[i-1], Get_Id(a[i]));
        for(int i = 1; i <= m; i++)
        {
            scanf("%d%d%d", &x, &y, &k);
            int _right = upper_bound(v.begin(), v.end(), k)-v.begin();
            //cout << "right: " << _right << endl;
            //note that: you should compare _right with 0, and if not, your code will tle
            printf("%d\n", _right ? query(1, Max_Size, root[x], root[y+1], 1, _right) : 0);
        }
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值