【洛谷P2617】Dynamic Rankings

題目大意:維護帶修改區間 K 小值。node

題解:學習到了樹狀數組套權值線段樹。 主席樹,即:可持久化權值線段樹,支持維護靜態區間的 K 小值問題,其核心思想是維護 N 棵權值線段樹,每一個線段樹維護的是序列 [1,i] 的權值,並根據可持久化思想使得空間複雜度維持在 $O(nlogn)$。 樹狀數組套權值線段樹,支持維護帶修改區間 K 小值的問題,其核心思想是改變靜態主席樹中各個權值線段樹的前綴和處理方式,在這裏採用樹狀數組中的前綴和處理方式,平衡了修改和查詢的時間和空間。時間和空間複雜度爲 $O(nlognlogn)$。注意:這裏 log 是以 2 爲底的對數。1e5 的 log2 大約爲16,所以內存開 300 倍。c++

代碼以下git

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;

inline int read(){
	int x=0,f=1;char ch;
	do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
	do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
	return f*x;
}

char opt[5];
int n,m,a[maxn],tmp[2][20],cnt[2];
int d[maxn<<1],len;
struct operation{bool tag;int l,r,k;int pos,val;}q[maxn];
struct node{
	#define ls(x) t[x].lc
	#define rs(x) t[x].rc
	int lc,rc,sum;
}t[maxn*300];
int tot,root[maxn];
inline void pushup(int o){t[o].sum=t[ls(o)].sum+t[rs(o)].sum;}
void insert(int &o,int l,int r,int pos,int val){
	if(!o)o=++tot;
	if(l==r){t[o].sum+=val;return;}
	int mid=l+r>>1;
	if(pos<=mid)insert(ls(o),l,mid,pos,val);
	else insert(rs(o),mid+1,r,pos,val);
	pushup(o);
}
int query(int l,int r,int k){
	if(l==r)return l;
	int mid=l+r>>1;
	int lsize=0;
	for(int i=1;i<=cnt[1];i++)lsize+=t[ls(tmp[1][i])].sum;
	for(int i=1;i<=cnt[0];i++)lsize-=t[ls(tmp[0][i])].sum;
	if(k<=lsize){
		for(int i=1;i<=cnt[1];i++)tmp[1][i]=ls(tmp[1][i]);
		for(int i=1;i<=cnt[0];i++)tmp[0][i]=ls(tmp[0][i]);
		return query(l,mid,k);
	}else{
		for(int i=1;i<=cnt[1];i++)tmp[1][i]=rs(tmp[1][i]);
		for(int i=1;i<=cnt[0];i++)tmp[0][i]=rs(tmp[0][i]);
		return query(mid+1,r,k-lsize);
	}
}
inline int lowbit(int x){return x&-x;}
inline void add(int x,int val){
	int pos=lower_bound(d+1,d+len+1,a[x])-d;
	for(int i=x;i<=n;i+=lowbit(i))insert(root[i],1,len,pos,val);
}
int querykth(int l,int r,int k){
	memset(tmp,0,sizeof(tmp)),cnt[1]=cnt[0]=0;
	for(int i=r;i;i-=lowbit(i))tmp[1][++cnt[1]]=root[i];
	for(int i=l-1;i;i-=lowbit(i))tmp[0][++cnt[0]]=root[i];
	return query(1,len,k);
}

void read_and_parse(){
	n=read(),m=read();
	for(int i=1;i<=n;i++)d[++len]=a[i]=read();
	for(int i=1;i<=m;i++){
		scanf("%s",opt);
		if(opt[0]=='Q')q[i].tag=0,q[i].l=read(),q[i].r=read(),q[i].k=read();
		else q[i].tag=1,q[i].pos=read(),d[++len]=q[i].val=read();
	}
	sort(d+1,d+len+1);
	len=unique(d+1,d+len+1)-d-1;
	for(int i=1;i<=n;i++)add(i,1);
}

void solve(){
	for(int i=1;i<=m;i++){
		if(q[i].tag){
			add(q[i].pos,-1);
			a[q[i].pos]=q[i].val;
			add(q[i].pos,1);
		}else{
			printf("%d\n",d[querykth(q[i].l,q[i].r,q[i].k)]);
		}
	}
}

int main(){
	read_and_parse();
	solve();
	return 0;
}
相關文章
相關標籤/搜索