zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    VIM 编辑器命令
    Ubuntu LAMP 便捷配置
    Linux基础命令
    Sql sever 定时任务设置
    C#自动发送邮件
    序列化与反序列化
    字符串.特殊引用类型
    抽象方法、接口
    函数的返回值
    线程
  • 原文地址:https://www.cnblogs.com/KirinSB/p/10766853.html
Copyright © 2011-2022 走看看