【可持久化线段树】【树状数组】[ZOJ 2112]Dynamic Rankings

题目大意:带修改操作的区间第K大
首先可以发现因为只有在需要使用的时候才会新建节点那么最多有 nlogn 个节点,那么只需要在更新的时候带上值域就可以不用进行离散化了,每一次就是和普通的树状数组那么进行更新,因为求得是区间的和(大概就是可持久化的原理)但是用树状数组来做每一个更新的时候就有了求前缀和的范围,每一次加起来就好了,其实和普通的树状数组差不多的。(注意是多组数据)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 500000;
const int INF = 1e9+7;
struct node{
    int ch[2];
    int sum;
}pool[20000000];
int roots[MAXN+10], n, m, tot;
int lowbit(int u){return (u&(-u));}
void Insert(int &u, int l, int r, int v, int k){
    ++tot;
    pool[tot] = pool[u];
    u = tot;
    pool[u].sum += k;
    if(l == r) return ;
    int mid = (l + r) >> 1;
    if(v <= mid) Insert(pool[u].ch[0], l, mid, v, k);
    else Insert(pool[u].ch[1], mid+1, r, v, k);
}
void Update(int u, int v, int k){
    while(u <= n){
        Insert(roots[u], -INF, INF, v, k);
        u += lowbit(u);
    }
}
int troots[MAXN+10], rcnt, lcnt;
void Q(int u){
    while(u > 0){
        troots[++rcnt] = roots[u];
        u -= lowbit(u);
    }
}
int A[MAXN+10];
int Query(int l, int r, int k){
    if(l >= r) return l;
    int cz = 0;
    for(int i=1;i<=lcnt;i++)
        cz += pool[pool[troots[i]].ch[0]].sum;
    for(int i=lcnt+1;i<=rcnt;i++)
        cz -= pool[pool[troots[i]].ch[0]].sum;
    int mid = (l + r) >> 1;
    if(k <= cz){
        for(int i=1;i<=rcnt;i++)
            troots[i] = pool[troots[i]].ch[0];
        return Query(l, mid, k);
    }
    for(int i=1;i<=rcnt;i++)
        troots[i] = pool[troots[i]].ch[1];
    return Query(mid+1, r, k-cz);
}
int main(){
        scanf("%d%d", &n, &m);
        for(int i=1;i<=n;i++){
            scanf("%d", &A[i]);
            Update(i, A[i], 1);
        }
        char s[10];
        int t1, t2, t3;
        for(int i=1;i<=m;i++){
            scanf("%s", s);
            if(s[0] == 'C'){
                scanf("%d%d", &t1, &t2);
                Update(t1, A[t1], -1);
                A[t1] = t2;
                Update(t1, A[t1], 1);
            }else{
                scanf("%d%d%d", &t1, &t2, &t3);
                rcnt = 0;
                Q(t2);
                lcnt = rcnt;
                Q(t1-1);
                printf("%d\n", Query(-INF, INF, t3));
            }
        }

    return 0;
}

你可能感兴趣的:(算法,ZOJ,树状数组,可持久化线段树)