树状数组套主席树

树状数组套主席树

学了个新技能,叫做树状数组套主席树

发现主席树不能修改,于是非常的郁闷

要是修改的话,一个版本改了,后面的版本都得改

于是想到了主席树其实就是一个大型的前缀和现场

想到用树状数组给他修理一下

于是我们就诞生了这个树状数组套主席树

用来解决主席树带修的问题

树状数组每一个节点都代表一个主席树的根

于是插入的时候直接往后跳就行了

查询的时候直接往前跳就行了

至于为什么不用线段树套主席树,因为没必要,并且无法pushup

动态排名系统

给你\(n\)个数,动态修改,每次询问\([l,r]\)区间中第\(k\)大的是多少

直接做,树状数组套主席树就行了

code
#include<bits/stdc++.h>
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
inline int read(){
    int s=0,t=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return s*t;
}
const int N=5e4+5;
int rt[N],R=1e9;
struct ZXS{
    struct POT{
        int sum,ls,rs;
    }tr[N*905];
    int seg;
    void clear(){
        fo(i,1,seg)tr[i].sum=tr[i].ls=tr[i].rs=0;
        seg=0;return ;
    }
    void ins(int &x,int l,int r,int pos,int v){
        if(!x)x=++seg;tr[x].sum+=v;
        if(l==r)return ;
        int mid=l+r>>1;
        if(pos<=mid)ins(tr[x].ls,l,mid,pos,v);
        else ins(tr[x].rs,mid+1,r,pos,v);
        return ;
    }
    int qa[N],qb[N],ca,cb;
    int query(int l,int r,int k){
        if(l==r)return l;
        int sum=0,mid=l+r>>1;
        fo(i,1,cb)sum+=tr[tr[qb[i]].ls].sum;
        fo(i,1,ca)sum-=tr[tr[qa[i]].ls].sum;
        if(sum>=k){
            fo(i,1,ca)qa[i]=tr[qa[i]].ls;
            fo(i,1,cb)qb[i]=tr[qb[i]].ls;
            return query(l,mid,k);
        }
        else {
            fo(i,1,ca)qa[i]=tr[qa[i]].rs;
            fo(i,1,cb)qb[i]=tr[qb[i]].rs;
            return query(mid+1,r,k-sum);
        }
    }
}zxs;
int T,n,q,a[N];
void add(int x,int v,int w){
    for(int i=x;i<=n;i+=(i&-i))zxs.ins(rt[i],1,R,v,w);
}
signed main(){
    T=read();
    while(T--){
        zxs.clear();
        fo(i,1,n)rt[i]=0;
        n=read();q=read();
        fo(i,1,n)add(i,a[i]=read(),1);
        while(q--){
            char tp[10];scanf("%s",tp+1);
            int l,r,k;
            if(tp[1]=='C'){
                l=read();r=read();
                add(l,a[l],-1);a[l]=r;
                add(l,a[l],1);
            }
            else {
                l=read();r=read();k=read();zxs.ca=zxs.cb=0;
                if(r-l+1<k){printf("-1\n");continue;}
                for(int i=l-1;i;i-=(i&-i))zxs.qa[++zxs.ca]=rt[i];
                for(int i=r;i;i-=(i&-i))zxs.qb[++zxs.cb]=rt[i];
                printf("%d\n",zxs.query(1,R,k));
            }
        }
    }
}

动态树排系统(瞎编的名字)

一棵树,节点权值动态修改,每次询问\(x\)\(y\)路径上的第\(k\)

这个如果是静态的话,直接按照父子关系建立主席树就行了

但是现在不行了,需要动态修改,我们仍然按照父子关系建立主席树

不过这次不能直接继承了

而是按照\(dfs\)序的关系动态修改,这样套上主席树就行了

纯口胡,无代码

posted @ 2021-12-16 08:41  fengwu2005  阅读(58)  评论(0编辑  收藏  举报