• 树状数组维护权值线段树


    Dynamic Rankings

    https://www.luogu.com.cn/problem/P2617

    题目描述

    给定一个含有 n n n 个数的序列 a 1 , a 2 … a n a_1,a_2 \dots a_n a1,a2an,需要支持两种操作:

    • Q l r k 表示查询下标在区间 [ l , r ] [l,r] [l,r] 中的第 k k k 小的数
    • C x y 表示将 a x a_x ax 改为 y y y

    输入格式

    第一行两个正整数 n , m n,m n,m,表示序列长度与操作个数。
    第二行 n n n 个整数,表示 a 1 , a 2 … a n a_1,a_2 \dots a_n a1,a2an
    接下来 m m m 行,每行表示一个操作,都为上述两种中的一个。

    输出格式

    对于每一次询问,输出一行一个整数表示答案。

    样例 #1

    样例输入 #1

    5 3
    3 2 1 4 7
    Q 1 4 3
    C 2 6
    Q 2 5 3
    
    • 1
    • 2
    • 3
    • 4
    • 5

    样例输出 #1

    3
    6
    
    • 1
    • 2

    提示

    【数据范围】

    对于 10 % 10\% 10% 的数据, 1 ≤ n , m ≤ 100 1\le n,m \le 100 1n,m100
    对于 20 % 20\% 20% 的数据, 1 ≤ n , m ≤ 1000 1\le n,m \le 1000 1n,m1000
    对于 50 % 50\% 50% 的数据, 1 ≤ n , m ≤ 1 0 4 1\le n,m \le 10^4 1n,m104
    对于 100 % 100\% 100% 的数据, 1 ≤ n , m ≤ 1 0 5 1\le n,m \le 10^5 1n,m105 1 ≤ l ≤ r ≤ n 1 \le l \le r \le n 1lrn 1 ≤ k ≤ r − l + 1 1 \le k \le r-l+1 1krl+1 1 ≤ x ≤ n 1\le x \le n 1xn 0 ≤ a i , y ≤ 1 0 9 0 \le a_i,y \le 10^9 0ai,y109

    请注意常数优化,但写法正常的整体二分和树套树都可以以大约 1000 ms 1000\text{ms} 1000ms 每个点的时间通过。

    来源:bzoj1901

    本题数据为洛谷自造数据,使用CYaRon耗时5分钟完成数据制作。

    学习笔记:

    动态维护区间 k k k / / /大值。
    我们做过静态的区间 k k k / / /大值,是采用前缀和的思想建前缀树,即主席树来解的。那么动态时,当更新节点时,我们需要改每颗树上的 l o g log log个节点,单次复杂度达到 n l o g n nlogn nlogn,显然不可取。
    那么我们同样看看,用前缀和的思想,能不能像权值线段树那样,模仿主席树那样跳节点找 k k k小呢 ? ?
    此时我们的外层就不在是主席树那样简单的 i − > i + 1 i->i+1 i>i+1的前缀方式了,这样会导致 n n n棵树互相关联;
    我们不想让他们关联,要方便修改,那么前缀就要换一种方式。
    此时就可以套上树状数组了。我们在树状数组的每个节点,代表的那一段区间里,开一个权值线段树,然后树状数组每个节点记录下此节点权值线段树里,数的个数,到时候我们查询时,就像主席树那样,用 1 1 1 r r r的总区间减去 1 1 1 l − 1 l-1 l1总区间,即得到 l l l r r r的权值情况。然后,树状数组里 1 1 1 r r r的总区间可能包含多个节点才能凑出来,所以不像主席树是两棵树在跳,这里是 2 ∗ l o g n 2*logn 2logn棵树一起跳,因为他们身上都有必要的前缀和信息。
    所以树状数组的作用是保存的是该区间值域内数的个数,方便查询;每个树状数组节点下的权值线段树的作用是维护该区间值域内数的个数,方便修改。
    复杂度就不说了,大佬那里说的很清楚。

    给个板子:

    /*keep on going and never give up*/
    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    #define ll long long
    #define db(x) cerr<<(#x)<<" "<<(x)<<" "<<endl;
    #define endl "\n"
    #define INF 1e17
    #define fast std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    const double E = exp(1);
    const double PI = acos(-1.0);
    const int maxn=2e5+10; 
    struct sgt{
    	int v,ls,rs;
    }t[maxn*100];
    struct dd{
    	bool b;
    	int l,r,k;
    	int pos,t;
    }q[maxn];
    int n,m,a[maxn],id[maxn<<1],rt[maxn],len,tot,temp[2][20],cnt[2];
    char op;
    void update(int &now,int l,int r,int pos,int val){
        if (!now) now=++tot;
        t[now].v+=val;
        if (l==r) return;
        int mid=l+r>>1;
        if (pos<=mid) update(t[now].ls,l,mid,pos,val);
        else update(t[now].rs,mid+1,r,pos,val);
    }
    void _update(int x,int val){
        int k=lower_bound(id+1,id+len+1,a[x])-id;
        for (int i=x;i<=n;i+=i&-i) update(rt[i],1,len,k,val);
    }
    int ask(int l,int r,int k){
        if (l==r) return l;
        int mid=l+r>>1,sum=0;
        for (int i=1;i<=cnt[1];i++) sum+=t[t[temp[1][i]].ls].v;
        for (int i=1;i<=cnt[0];i++) sum-=t[t[temp[0][i]].ls].v;
        if (k<=sum){
            for (int i=1;i<=cnt[1];i++) temp[1][i]=t[temp[1][i]].ls;
            for (int i=1;i<=cnt[0];i++) temp[0][i]=t[temp[0][i]].ls;
            return ask(l,mid,k);
        }
        else{
            for (int i=1;i<=cnt[1];i++) temp[1][i]=t[temp[1][i]].rs;
            for (int i=1;i<=cnt[0];i++) temp[0][i]=t[temp[0][i]].rs;
            return ask(mid+1,r,k-sum);
        }
    }
    int _ask(int l,int r,int k){
        memset(temp,0,sizeof(temp));
        cnt[0]=cnt[1]=0;
        for (int i=r;i;i-=i&-i) temp[1][++cnt[1]]=rt[i];
        for (int i=l-1;i;i-=i&-i) temp[0][++cnt[0]]=rt[i];
        return ask(1,len,k);
    }
    signed main(){
        fast
        cin>>n>>m;
        for (int i=1;i<=n;i++) cin>>a[i],id[++len]=a[i];
        for (int i=1;i<=m;i++){
            cin>>op;
            q[i].b=(op=='Q');
            if (q[i].b)    cin>>q[i].l>>q[i].r>>q[i].k;
            else cin>>q[i].pos>>q[i].t,id[++len]=q[i].t;
        }
        sort(id+1,id+len+1);
        len=unique(id+1,id+len+1)-id-1;
        for (int i=1;i<=n;i++) _update(i,1);
        for (int i=1;i<=m;i++){
            if (q[i].b) printf("%d\n",id[_ask(q[i].l,q[i].r,q[i].k)]);
            else{
                _update(q[i].pos,-1);
                a[q[i].pos]=q[i].t;
                _update(q[i].pos,1);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
  • 相关阅读:
    CSS中的层叠上下文
    Android入门第39天-系统设置Configuration类
    MySQL常用命令
    3 步排查,3 步优化,探针性能损耗直降 44%
    jmeter调试错误大全
    Pytorch中张量的高级选择操作
    会计事业怎么实施RPA新员工增加客户的互动
    SOCKS55代理与Http代理有何区别?如何选择?
    docker学习:dockerfile和docker-compose
    JAVA计算机毕业设计社区智能化管理源码+系统+mysql数据库+lw文档
  • 原文地址:https://blog.csdn.net/qq_62539009/article/details/125498599