动态查询区间第k大

Dynamic Rankings

注:这道题也有树套树和整体二分的做法,这里讲解的是主席树 + 树状数组思路优化。

尝试沿用上一题的思路,思考修改操作如何完成:

考虑到修改操作对每棵权值线段树的影响是:

设修改前的值为w,则[1,x](xi<=x<=n)的线段树都把值域为w的点−1
[1,x](xi<=x<=n)的线段树都把值域为vali的点+1
这样做的时间复杂度过高,我们可以考虑用树状数组的二进制思想进行优化:

T[i]这颗线段树代表[i−lowbit(x)+1,x]这段区间建成的线段树:

修改操作,最多修改log2n颗线段树即可。
查询操作,用不超过2∗log2n颗线段树就能拼(前缀和)出[li,ri]的线段树。
注意,在查询时的代码实现:

用X数组存储拼出[1,x−1]的所有点。
用Y数组存储拼出[1,y]的所有点。
然后用普通主席树的方法,让所有的跟着跳,对位相减即可。

时间复杂度O(nlog2n)O(nlog2n), 空间复杂度O(2n+(n+m)log2n)

 

#include <bits/stdc++.h>

using namespace std;

const int maxn=250000;
const int M=250000*400;
int n,q,m,tot;
int a[maxn],t[maxn];
int T[maxn],lson[M],rson[M],c[M];
int S[maxn];
struct Query{
    int kind;
    int l,r,k;
}query[100100];
void init_hash(int k){
    sort(t,t+k);
    m=unique(t,t+k)-t;
}
int hash1(int x){
    return lower_bound(t,t+m,x)-t;
}

int build(int l,int r) {
    int root = tot++;
    c[root] = 0;
    if (l != r) {
        int mid = (l + r) >> 1;
        lson[root] = build(l, mid);
        rson[root] = build(mid + 1, r);
    }
    return root;
}

int insert(int root,int pos,int val) {
    int newroot = tot++, tmp = newroot;
    int l = 0, r = m - 1;
    c[newroot] = c[root] + val;
    while (l < r) {
        int mid = (l + r) >> 1;
        if (pos <= mid) {
            lson[newroot] = tot++;
            rson[newroot] = rson[root];
            newroot = lson[newroot];
            root = lson[root];
            r = mid;
        } else {
            rson[newroot] = tot++;
            lson[newroot] = lson[root];
            newroot = rson[newroot];
            root = rson[root];
            l = mid + 1;
        }
        c[newroot] = c[root] + val;
    }
    return tmp;
}

int lowbit(int x) {
    return x & -x;
}

int use[maxn];

int sum(int x) {
    int ret = 0;
    while (x) {
        ret += c[lson[use[x]]];
        x -= lowbit(x);
    }
    return ret;
}

int Query(int left,int right,int k) {
    int left_root = T[left - 1];
    int right_root = T[right];
    int l = 0, r = m - 1;
    for (int i = left - 1; i; i -= lowbit(i)) use[i] = S[i];
    for (int i = right; i; i -= lowbit(i)) use[i] = S[i];
    while (l < r) {
        int mid = (l + r) >> 1;
        int tmp = sum(right) - sum(left - 1) + c[lson[right_root]] - c[lson[left_root]];
        if (tmp >= k) {
            r = mid;
            for (int i = left - 1; i; i -= lowbit(i)) use[i] = lson[use[i]];
            for (int i = right; i; i -= lowbit(i)) use[i] = lson[use[i]];
            left_root = lson[left_root];
            right_root = lson[right_root];
        } else {
            l = mid + 1;
            k -= tmp;
            for (int i = left - 1; i; i -= lowbit(i)) use[i] = rson[use[i]];
            for (int i = right; i; i -= lowbit(i)) use[i] = rson[use[i]];
            left_root = rson[left_root];
            right_root = rson[right_root];
        }
    }
    return l;
}

void Modify(int x,int p,int d) {
    while (x <= n) {
        S[x] = insert(S[x], p, d);
        x += lowbit(x);
    }
}

int main() {
    scanf("%d%d", &n, &q);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        t[m++] = a[i];
    }
    char op[10];
    for (int i = 0; i < q; i++) {
        scanf("%s", op);
        if (op[0] == 'Q') {
            query[i].kind = 0;
            scanf("%d%d%d", &query[i].l, &query[i].r, &query[i].k);
        } else {
            query[i].kind = 1;
            scanf("%d%d", &query[i].l, &query[i].r);
            t[m++] = query[i].r;
        }
    }
    init_hash(m);
    T[0] = build(0, m - 1);
    for (int i = 1; i <= n; i++) {
        T[i] = insert(T[i - 1], hash1(a[i]), 1);
    }
    for (int i = 1; i <= n; i++) {
        S[i] = T[0];
    }
    for (int i = 0; i < q; i++) {
        if (query[i].kind == 0) {
            printf("%d\n", t[Query(query[i].l, query[i].r, query[i].k)]);
        } else {
            Modify(query[i].l, hash1(a[query[i].l]), -1);
            Modify(query[i].l, hash1(query[i].r), 1);
            a[query[i].l] = query[i].r;
        }
    }
    return 0;
}

HDU 5412 CRB and Queries【整体二分+树状数组】

 

posted @ 2019-08-29 09:48  Snow_in_winer  阅读(434)  评论(0编辑  收藏  举报