Super Mario 主席树 hdu-4417

该博客介绍了一种使用主席树数据结构解决马里奥跳跃问题的方法。题目中,给定一定数量的墙和多次查询,要求计算马里奥在给定跳跃高度下能跳过的墙的数量。博主通过离散化墙的高度,维护每个区间内不同墙体数量,利用前缀和快速求解。代码中展示了如何构建和更新主席树,并进行区间查询。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:Problem - 4417

题面:

 

题意:有n个墙,m次查询,下面给每个墙的高度,每次查询给左区间,右区间和马里奥跳跃的最高高度,问马里奥可以跳上几座墙

思路:主席树,可以通过离散化的方法,把墙的高度离散下去,然后维护从第一面墙到第i面墙中一共的不同墙体的数量,然后通过前缀和的思想可以快速求值

#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
#define N 100005
int a[N];
vector<int> ve;
struct node{
    int num;//存这个区间内总墙体数量
    int lson;
    int rson;
}tree[N * 40];
int root[N];
int cnt = 0;
void pushup(int rt){
    tree[rt].num = tree[tree[rt].lson].num + tree[tree[rt].rson].num;
}
int build(int l, int r, int rt){
    tree[++cnt] = tree[rt];
    rt = cnt;
    if(l == r){
        tree[rt].num = 0;
        return rt;
    }
    int mid = (l + r) / 2;
    tree[rt].lson = build(l, mid, tree[rt].lson);
    tree[rt].rson = build(mid + 1, r, tree[rt].rson);
    pushup(rt);
    return rt;
}
int find(int x){
    return lower_bound(ve.begin(), ve.end(), x) - ve.begin() + 1;
}
int updata(int l, int r, int rt, int k){
    tree[++cnt] = tree[rt];
    rt = cnt;
    if(l == r){ //将高为k的墙体数量++
        tree[rt].num ++;
        return rt;
    }
    int mid = (l + r) / 2;
    if(k <= mid){
        tree[rt].lson = updata(l, mid, tree[rt].lson, k);
    }else{
        tree[rt].rson = updata(mid + 1, r, tree[rt].rson, k);
    }
    pushup(rt);
    return rt;
}
int query(int l, int r, int L, int R, int k){
    if(r <= k){
        return tree[R].num - tree[L].num;
    }
    int mid = (l + r) / 2;
    if(k <= mid){
        return query(l, mid, tree[L].lson, tree[R].lson, k);
    }else{
        int ans = 0;
        ans += query(l, mid, tree[L].lson, tree[R].lson, k);
        ans += query(mid + 1, r, tree[L].rson, tree[R].rson, k);
        return ans;
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int ans = 1;
    int t;
    cin >> t;
    while(t--){
        cnt = 0;
        int n, m;
        cin >> n >> m;
        ve.clear();
        for(int i = 1; i <= n; i++){
            cin >> a[i];
            ve.push_back(a[i]);
        }
        sort(ve.begin(), ve.end());
        ve.erase(unique(ve.begin(), ve.end()), ve.end());
        root[0] = build(1, ve.size(), 0);
        for(int i = 1; i <= n; i++){//加上这面墙是一个新的线段树
            root[i] = updata(1, ve.size(), root[i - 1], find(a[i]));
        }
        cout << "Case " << ans++ << ":" << endl;
        for(int i = 0; i < m; i++){
            int l, r, h;
            cin >> l >> r >> h;
            l++;
            r++;
            int k = find(h);
            if(k == 1 && ve[0] > h){
                cout << 0 << endl;
            }else {
                if(k == ve.size() + 1){
                    k--;
                }else if(ve[k - 1] != h){
                    k--;
                }
                cout << query(1, ve.size(), root[l - 1], root[r], k) << endl;
            }
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值