P2617 Dynamic Rankings

hzy_____l發表於2024-03-27

\(Dynamic Rankings\)

動態主席樹。

在主席樹的基礎上加上單點修改。

考慮用樹狀陣列套權值線段樹。樹狀陣列的每個節點都由一個權值線段樹來維護。


  • 修改:這沒什麼好說的,就是對樹狀陣列中需要修改的節點的權值線段樹進行單點修改即可。對於將 \(a_i\) 修改為 \(x\) ,就先消除原 \(a_i\) 的影響,再加上 \(x\) 的影響即可。
void add(int l,int r,int &n,int x,int y){
    if(!n)n=++tot;
    t[n].x+=y;
    if(l==r)return;
    int mid=l+r>>1;
    if(x<=mid)add(l,mid,lc(n),x,y);
    else add(mid+1,r,rc(n),x,y);
    update(n);
}
inline void add1(int k,int x,int y){
	for(;k<=n;k+=k&(-k))add(1,1e9,tr[k],x,y);
}
add1(k,a[k],-1);
add1(k,x,1);
a[k]=x;
  • 查詢:對於區間 \([l,r]\) ,提前處理出其在樹狀陣列中需要統計的節點。再同時遍歷這些權值線段樹進行求解即可。
int ask(int l,int r,int x[],int lx,int y[],int ly,int k){
	if(l==r)return l;
	int mid=l+r>>1;
	int s=0;
	for(int i=1;i<=ly;i++)s+=t[lc(y[i])].x;
	for(int i=1;i<=lx;i++)s-=t[lc(x[i])].x;
	if(k<=s){
		for(int i=1;i<=ly;i++)y[i]=lc(y[i]);
		for(int i=1;i<=lx;i++)x[i]=lc(x[i]);
		return ask(l,mid,x,lx,y,ly,k);
	}
	else{
		for(int i=1;i<=ly;i++)y[i]=rc(y[i]);
		for(int i=1;i<=lx;i++)x[i]=rc(x[i]);
		return ask(mid+1,r,x,lx,y,ly,k-s);
	}
}
int ask1(int x,int y,int k){
	lx=ly=0;
	for(;x;x-=x&(-x))xx[++lx]=tr[x];
	for(;y;y-=y&(-y))yy[++ly]=tr[y];
	return ask(1,1e9,xx,lx,yy,ly,k);
}

由於是動態開點,所以不用離散化。

時間,空間複雜度均為 \(n\times log^2n\)

Code:

#include<bits/stdc++.h>
#define lc(x) t[x].lc
#define rc(x) t[x].rc
using namespace std;
const int N=1e5+10;
struct p{int lc,rc,x;}t[N*300];
int tr[N],ans[N],tot,n,a[N],x,y,k,m,xx[N],yy[N],lx,ly;
char op;
inline void update(int n){t[n].x=t[lc(n)].x+t[rc(n)].x;}
void add(int l,int r,int &n,int x,int y){
    if(!n)n=++tot;
    t[n].x+=y;
    if(l==r)return;
    int mid=l+r>>1;
    if(x<=mid)add(l,mid,lc(n),x,y);
    else add(mid+1,r,rc(n),x,y);
    update(n);
}
int ask(int l,int r,int x[],int lx,int y[],int ly,int k){
	if(l==r)return l;
	int mid=l+r>>1;
	int s=0;
	for(int i=1;i<=ly;i++)s+=t[lc(y[i])].x;
	for(int i=1;i<=lx;i++)s-=t[lc(x[i])].x;
	if(k<=s){
		for(int i=1;i<=ly;i++)y[i]=lc(y[i]);
		for(int i=1;i<=lx;i++)x[i]=lc(x[i]);
		return ask(l,mid,x,lx,y,ly,k);
	}
	else{
		for(int i=1;i<=ly;i++)y[i]=rc(y[i]);
		for(int i=1;i<=lx;i++)x[i]=rc(x[i]);
		return ask(mid+1,r,x,lx,y,ly,k-s);
	}
}
inline void add1(int k,int x,int y){
	for(;k<=n;k+=k&(-k))add(1,1e9,tr[k],x,y);
}
int ask1(int x,int y,int k){
	lx=ly=0;
	for(;x;x-=x&(-x))xx[++lx]=tr[x];
	for(;y;y-=y&(-y))yy[++ly]=tr[y];
	return ask(1,1e9,xx,lx,yy,ly,k);
}
signed main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		add1(i,a[i],1);
	}
	while(m--){
		scanf("%s",&op);
		if(op=='C'){
			scanf("%d%d",&k,&x);
			add1(k,a[k],-1);
			add1(k,x,1);
			a[k]=x;
		}else{
			scanf("%d%d%d",&x,&y,&k);
			printf("%d\n",ask1(x-1,y,k));
		}
	}
}

相關文章