HDU - 4417 Super Mario 【主席树 】 询问区间中小于等于某个数的个数

传送门
题目大意: 询问区间中小于等于某个数的个数

思路: 没什么好说的,,, 就是一个模板题, 会求区间第k大, 就会求这个.

const int maxn = 1e5+5;
int n, m;
struct Tree {
    int ls, rs, val; // 左右儿子的编号, 和维护的一个值.
}tre[maxn*40];
int idx, root[maxn];
int build(int l, int r) {
    int nod = ++idx;
    tre[nod].val = 0;
    if (l == r) return nod;
    int mid = (l + r) >> 1;
    tre[nod].ls = build(l, mid);
    tre[nod].rs = build(mid+1, r);
    return nod;
}
int update(int pre, int l, int r, int pos, int v) {
    int nod = ++idx;
    tre[nod] = tre[pre]; tre[nod].val += v;
    if (l == r) return nod;
    int mid = (l + r) >> 1;
    if (pos <= mid) tre[nod].ls = update(tre[pre].ls, l, mid, pos, v);
    else tre[nod].rs = update(tre[pre].rs, mid+1, r, pos, v);
    return nod;
}
int query(int ql, int qr, int l, int r, int pos) {
    if (l == r) return tre[qr].val - tre[ql].val;
    int mid = (l + r) >> 1;
    int num = tre[tre[qr].ls].val - tre[tre[ql].ls].val;
    if (pos > mid) {
        return num + query(tre[ql].rs, tre[qr].rs, mid+1, r, pos);
    }
    else return query(tre[ql].ls, tre[qr].ls, l, mid, pos);
}
int a[maxn];
vector<int>ve;
int getid(int x) {
    return upper_bound(ve.begin(), ve.end(), x) - ve.begin();
}
void solve() {
    scanf("%d%d", &n, &m);
    ve.clear(); idx = 0;
    for (int i = 1 ; i <= n ; i ++) {
        scanf("%d", a+i);
        ve.pb(a[i]);
    }
    sort(ve.begin(), ve.end());
    ve.erase(unique(ve.begin(), ve.end()), ve.end());
    root[0] = build(1, sz(ve));    //根节点
    for (int i = 1 ; i <= n ; i ++) {
        int pos = getid(a[i]);
        root[i] = update(root[i-1], 1, sz(ve), pos, 1);
    }
    while (m--) {
        int l, r, k; scanf("%d%d%d", &l, &r, &k);
        ++l; ++r; int pos = getid(k);
        if (!pos) puts("0");
        else {int tmp = query(root[l-1], root[r], 1, sz(ve), pos);
        printf("%d\n", tmp);
        }
    }
}

如果是求小于等于某个数的数字之和, 那么把次数1改成相应的权值val[i]即可呀, 一样的~~~

猜你喜欢

转载自blog.csdn.net/Anxdada/article/details/81280922
今日推荐