主席树区间动态第K大学习笔记 大佬们的博客 Some Links

模板题:

bzoj1901

学习笔记:

静态的区间第K大主席树用到了这么一个思想,就是维护不同的前缀权值线段树,利用不同区间的权值线段树可减的思想来达到查询某一区间的权值线段树的目的。
但是一旦要求修改的话,利用上面那种维护前缀权值线段树就有点麻烦了,因为修改一个值之后所有包括了这个值的前缀权值线段树都要修改,复杂度显然是有问题的。
然后动态的主席树便换了一种思路,想一想如果只是动态的前缀和我们要怎么维护?那就是用树状数组。这里也用到了树状数组的思想,即一个主席树并不维护一段前缀权值线段树,而是维护 [ i l o w b i t ( i ) + 1 , i ] 这一段的权值线段树,这样查询的时候要利用到 l o g   n 个权值线段树的信息,复杂度达到了 l o g 2   n ,但是如果单点修改某一个位置的值的话,就只需要更新 l o g   n 个权值线段树。

#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a;i<=b;++i)
typedef long long ll;

using namespace std;

void File(){
    freopen("bzoj1901.in","r",stdin);
    freopen("bzoj1901.out","w",stdout);
}

template<typename T>void read(T &_){
    T __=0,mul=1; char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')mul=-1;
        ch=getchar();
    }
    while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
    _=__*mul;
}

const int maxn=1e4+10;
int n,m,a[maxn],b[maxn<<1],tot;
int ql[maxn],qr[maxn],qk[maxn],cntc;
bool ty[maxn];

int root[maxn],Lrt[maxn],Rrt[maxn];
int lowbit(int x){return x&(-x);}
struct Chairman_Tree{
#define mid ((l+r)>>1)
    int lc[maxn<<8],rc[maxn<<8],sum[maxn<<8],cnt;
    void update(int &rt,int l,int r,int pos,int x){
        if(!rt)rt=++cnt; sum[rt]+=x;
        if(l==r)return;
        if(pos<=mid)update(lc[rt],l,mid,pos,x);
        else update(rc[rt],mid+1,r,pos,x);
    }
    int query(int Lsz,int Rsz,int l,int r,int k){
        if(l==r)return l;
        int val=0;
        REP(i,1,Lsz)val-=sum[lc[Lrt[i]]];
        REP(i,1,Rsz)val+=sum[lc[Rrt[i]]];
        if(k<=val){
            REP(i,1,Lsz)Lrt[i]=lc[Lrt[i]];
            REP(i,1,Rsz)Rrt[i]=lc[Rrt[i]];
            return query(Lsz,Rsz,l,mid,k);
        }
        else{
            REP(i,1,Lsz)Lrt[i]=rc[Lrt[i]];
            REP(i,1,Rsz)Rrt[i]=rc[Rrt[i]];
            return query(Lsz,Rsz,mid+1,r,k-val);
        }
    }
}T;

void init(){
    read(n); read(m);
    REP(i,1,n)read(a[i]),b[i]=a[i];
    char s[5];
    REP(i,1,m){
        scanf("%s",s);
        if(s[0]=='Q')ty[i]=0,read(ql[i]),read(qr[i]),read(qk[i]);
        else ty[i]=1,read(ql[i]),read(qr[i]),b[n+(++cntc)]=qr[i];
    }
    sort(b+1,b+n+cntc+1);
    tot=unique(b+1,b+n+cntc+1)-b-1;
}

int get_num(int x){return lower_bound(b+1,b+tot+1,x)-b;}

void modify(int num,int pos,int x){
    while(num<=n){
        T.update(root[num],1,tot,pos,x);
        num+=lowbit(num);
    }
}

int get_ans(int l,int r,int k){
    int Lsz=0,Rsz=0;
    while(l>=1)Lrt[++Lsz]=root[l],l-=lowbit(l);
    while(r>=1)Rrt[++Rsz]=root[r],r-=lowbit(r);
    return T.query(Lsz,Rsz,1,tot,k);
}

void work(){
    REP(i,1,n)modify(i,get_num(a[i]),1);
    REP(i,1,m){
        if(ty[i]==0){
            int num=get_ans(ql[i]-1,qr[i],qk[i]);
            printf("%d\n",b[num]);
        }
        else{
            modify(ql[i],get_num(a[ql[i]]),-1);
            modify(ql[i],get_num(qr[i]),1);
            a[ql[i]]=qr[i];
        }
    }
}

int main(){
    File();
    init();
    work();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ylsoi/article/details/81771909
今日推荐