Super Mario(主席树)

  • Post author:
  • Post category:其他

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;
}

版权声明:本文为weixin_40788897原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。