主席树模板(带修改)

P2617 Dynamic Rankings

  • 显然单单写一个主席树是不够的,主席树可以维护的是静态区间第k大。本题要求动态修改,所以考虑带修改的主席树怎么写。
  • 首先很显然一个小thick是,我们把修改的部分和原本静态的分开,单独形成新的主席树。这样的好处有很多:处理方便,思路清晰,更好理解题目。
  • 如果暴力修改的话,每次修改一个点,我们最多需要修改n棵线段树。所以复杂度太高,无法接受。其实带修改的主席树,就是树套树嘛,主席树套了一个树状数组,把每棵线段树当成一个点,你就好理解了。和树状数组是一样的,本来我们维护一个前缀和,可以O(1)查询区间和。但是修改是O(n)的。用了树状数组以后,我们修改是log的,查询也是log的。同理,套了树状数组以后,我们每次修改只需要修改log棵线段树,查询也是。所以总的复杂度是 O ( n l o g 2 n ) O(nlog^2n)
  • 关于代码实现:
    (1)因为中间修改的时候会新建立节点,所以空间开的时候乘50或者再大一点,否则RE。
    (2)为了方便查询,我们有一个s数组。s[i]表示在第i个节点被修改过之后所在的节点。
    (3)查询的时候,为了方便,我们提前把需要计算到的节点编号存在数组里面。注意好想象的“点”与线段树的联系。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e5+10;
int n,m,tot,sz,num,a[N],b[N],rt[N],s[N],sum[N*300],ls[N*300],rs[N*300],rootl[50],rootr[50],cntl,cntr;
struct node{
	int l,r,k,op;
}q[N];
int get(int x){return lower_bound(b+1,b+sz+1,x)-b;}
int lowbit(int x){return x&(-x);}
struct Tree{
	void update(int &o,int pre,int l,int r,int x){
		o=++tot;
		sum[o]=sum[pre]+1;
		ls[o]=ls[pre];
		rs[o]=rs[pre];
		if(l==r) return;
		int mid=l+r>>1;
		if(x<=mid) update(ls[o],ls[pre],l,mid,x);
		else update(rs[o],rs[pre],mid+1,r,x);
	}
	void add_update(int &o,int l,int r,int x,int val){
		if(o==0) o=++tot;
		sum[o]+=val;
		if(l==r) return;
		int mid=l+r>>1;
		if(x<=mid) add_update(ls[o],l,mid,x,val);
		else add_update(rs[o],mid+1,r,x,val);
	}
	void add_update(int k,int val){
		int x=get(a[k]);int y=get(val);
		a[k]=val;
		while(k<=n){
			add_update(s[k],1,sz,x,-1);
			add_update(s[k],1,sz,y,1);
			k+=lowbit(k);
		}
	}
	int query(int last,int now,int l,int r,int x){
        if(l==r) return l;
        int cnt=sum[ls[now]]-sum[ls[last]];
        for(int i=1;i<=cntl;++i) cnt-=sum[ls[rootl[i]]];
        for(int i=1;i<=cntr;++i) cnt+=sum[ls[rootr[i]]];
        int mid=l+r>>1;
        if(cnt>=x){
            for(int i=1;i<=cntl;++i) rootl[i]=ls[rootl[i]];
            for(int i=1;i<=cntr;++i) rootr[i]=ls[rootr[i]];
            return query(ls[last],ls[now],l,mid,x);
        }else{
            for(int i=1;i<=cntl;++i) rootl[i]=rs[rootl[i]];
            for(int i=1;i<=cntr;++i) rootr[i]=rs[rootr[i]];
            return query(rs[last],rs[now],mid+1,r,x-cnt);
        }
    }
	int kth(int l,int r,int k){
		cntl=cntr=0;
		for(int i=l-1;i;i-=lowbit(i)) rootl[++cntl]=s[i];
		for(int i=r;i;i-=lowbit(i)) rootr[++cntr]=s[i];
		int ans=query(rt[l-1],rt[r],1,sz,k);
		return b[ans];
	}
}tr;
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i) scanf("%d",&a[i]),b[++sz]=a[i];
	for(int i=1;i<=m;++i){
		char ch;scanf(" %c",&ch);
		if(ch=='Q'){q[i].op=1;
			scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].k);
		}else{q[i].op=2;
			scanf("%d%d",&q[i].l,&q[i].r);b[++sz]=q[i].r;
		}
	}
	sort(b+1,b+sz+1);
	int num=unique(b+1,b+sz+1)-b-1;
	sz=num;
	for(int i=1;i<=n;++i) tr.update(rt[i],rt[i-1],1,sz,get(a[i]));
	for(int i=1;i<=m;++i){
		if(q[i].op==1){
			printf("%d\n",tr.kth(q[i].l,q[i].r,q[i].k));
		}else{
			tr.add_update(q[i].l,q[i].r);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39759315/article/details/88955315