ZOJ 2112 Dynamic Rankings(树状数组套主席树 可修改区间第k小)题解

题意:求区间第k小,节点可修改

思路:如果直接用静态第k小去做,显然我更改一个节点后,后面的树都要改,这个复杂度太高。那么我们想到树状数组思路,树状数组是求前缀和,那么我们可以用树状数组套主席树,求出权值线段树前缀和,相减就是区间前缀和。而且我维护也只要改logn棵树就好了。具体看JQ博客

代码:

#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include <iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 5e4 + 10;
const int M = maxn * 30;
const ull seed = 131;
const int INF = 0x3f3f3f3f;
const int MOD = 1000000007;
int a[maxn], root[maxn], tot;
int sroot[maxn];    //树状数组的头
int use[maxn];  //保存树状数组的头
int n, m, L, R;
vector<int> vv;
struct node{
    int lson, rson;
    int sum;
}T[maxn * 40];
struct Que{
    int order;
    int l, r, k;
}q[maxn];
void init(){
    memset(T, 0, sizeof(T));
    memset(sroot, 0, sizeof(root));
    tot = 0;
    vv.clear();
}
int lowbit(int x){
    return x&(-x);
}
int getId(int x){
    return lower_bound(vv.begin(), vv.end(),x) - vv.begin() + 1;
}
void update(int l, int r, int &now, int pre, int v, int pos){
    T[++tot] = T[pre], T[tot].sum += v, now = tot;
    if(l == r) return;
    int m = (l + r) >> 1;
    if(pos <= m)
        update(l, m, T[now].lson, T[pre].lson, v, pos);
    else
        update(m + 1, r, T[now].rson, T[pre].rson, v, pos);
}
int add(int x, int v, int pos){
    for(int i = x; i <= n; i += lowbit(i)){
        update(1, vv.size(), sroot[i], sroot[i], v, pos);
    }
}
int SUM(int pos){
    int ret = 0;
    for(int i = pos; i > 0; i -= lowbit(i))
        ret += T[T[use[i]].lson].sum;
    return ret;
}

int query(int l, int r, int now, int pre, int k){
    if(l == r) return l;
    int sum = SUM(R) - SUM(L) + T[T[now].lson].sum - T[T[pre].lson].sum;
    int m = (l + r) >> 1;
    if(sum >= k){
        for(int i = R; i > 0; i -= lowbit(i)) use[i] = T[use[i]].lson;
        for(int i = L; i > 0; i -= lowbit(i)) use[i] = T[use[i]].lson;
        return query(l, m, T[now].lson, T[pre].lson, k);
    }
    else{
        for(int i = R; i > 0; i -= lowbit(i)) use[i] = T[use[i]].rson;
        for(int i = L; i > 0; i -= lowbit(i)) use[i] = T[use[i]].rson;
        return query(m + 1, r, T[now].rson, T[pre].rson, k - sum);
    }
}

int main(){
    int T;
    scanf("%d", &T);
    while(T--){
        init();
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++){
            scanf("%d", &a[i]);
            vv.push_back(a[i]);
        }
        for(int i = 1; i <= m; i++){
            char o[5];
            scanf("%s", o);
            if(o[0] == 'Q'){
                q[i].order = 0;
                scanf("%d%d%d", &q[i].l, &q[i].r, &q[i].k);
            }
            else{
                q[i].order = 1;
                scanf("%d%d", &q[i].l, &q[i].k);
                vv.push_back(q[i].k);
            }
        }

        sort(vv.begin(), vv.end());
        vv.erase(unique(vv.begin(), vv.end()), vv.end());

        for(int i = 1; i <= n; i++){
            update(1, vv.size(), root[i], root[i - 1], 1, getId(a[i]));
        }
        for(int i = 1; i <= m; i++){
            if(q[i].order == 0){
                L = q[i].l - 1, R = q[i].r;
                for(int j = R; j > 0; j -= lowbit(j)) use[j] = sroot[j];
                for(int j = L; j > 0; j -= lowbit(j)) use[j] = sroot[j];
                printf("%d
", vv[query(1, vv.size(), root[R], root[L], q[i].k) - 1]);
            }
            else{
                add(q[i].l, -1, getId(a[q[i].l]));
                a[q[i].l] = q[i].k;
                add(q[i].l, 1, getId(a[q[i].l]));
            }
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/KirinSB/p/10766853.html