1. 程式人生 > 其它 >樹狀陣列套主席樹

樹狀陣列套主席樹

樹狀陣列套主席樹

學了個新技能,叫做樹狀陣列套主席樹

發現主席樹不能修改,於是非常的鬱悶

要是修改的話,一個版本改了,後面的版本都得改

於是想到了主席樹其實就是一個大型的字首和現場

想到用樹狀陣列給他修理一下

於是我們就誕生了這個樹狀陣列套主席樹

用來解決主席樹帶修的問題

樹狀陣列每一個節點都代表一個主席樹的根

於是插入的時候直接往後跳就行了

查詢的時候直接往前跳就行了

至於為什麼不用線段樹套主席樹,因為沒必要,並且無法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\)序的關係動態修改,這樣套上主席樹就行了

純口胡,無程式碼