ZOJ - 2112 Dynamic Rankings 樹套樹(樹狀數組套主席樹)

要理解這題的話 首先得理解一下主席樹上面的前綴和思想  我們求區間L~R第k小的時候  是用R這顆樹的值減去(L-1)這棵樹的值 這其中暗含了 L~R的數值在值域上的分佈(瞎說) 通過這個分佈我們可以向第k小靠攏   R和L-1的差值 這不是顯然的前綴和思想嗎   那普通的主席樹我們其實可以看成數組的前綴和  當我要知道 區間L到R的值時  我就訪問 R和L-1的差值   並且這是不帶修改的 

那如果是需要單點修改的主席樹呢?  我們單點修改的數組是如何做的?  對 用樹狀數組來維護 達到單點修改和詢問的目的  那麼思路就出來了  樹狀數組維護主席樹 快速進行主席樹的單點修改  複雜度是nlognlogn的

但是在zoj上 空間太小了 以至於我們不能把原始數組也插入這樣的樹套樹結構(空間複雜度 nlognlogn+mlognlogn)其中n比較大  我們又想一想 當我們用樹狀數組去維護的數組的時候 是不是也有不需要把初始數組輸入樹狀數組的方法?  yes  我們只需要維護在初始數組上的變化就行了  假如維護的是a數組  詢問ai  那麼 ai=query(R)-query(L-1)+Ai 其中Ai是ai的初始值

那麼通過這樣的想法 我們把主席樹類比成數組 我們可以建立一顆初始的主席樹(關於初始數組的)  然後再結合樹套樹就可以完成了 這樣的空間複雜的是 nlogn+mlognlogn 可以過    

#include<bits/stdc++.h>
using namespace std;
const int N = 6e4+100;
const int M = 2600000;
int n,q,m,tot;
int a[N],t[N],T[N],S[N];
int lson[M],rson[M],c[M];
struct Query{
	int l,r,k;
	bool f;
}p[10010];
int Hash(int x){
	return lower_bound(t+1,t+1+m,x)-t;
}
void update(int &rt,int lasrt,int l,int r,int pos,int val){
	int mid = l+r>>1;rt=++tot;c[rt]=c[lasrt]+val;
	if(l==r) return;
	if(pos<=mid) rson[rt]=rson[lasrt],update(lson[rt],lson[lasrt],l,mid,pos,val);
	else lson[rt]=lson[lasrt],update(rson[rt],rson[lasrt],mid+1,r,pos,val);
}
int use[N];
void add(int x,int pos,int d){
	while(x<=n){
		update(S[x],S[x],1,m,pos,d);
		x+=x&-x;
	}
}
int sum(int x){
	int ret = 0;
	while(x){
		ret+=c[lson[use[x]]];
		x-=x&-x;
	}
	return ret;
}
int query(int left,int right,int Tl,int Tr,int l,int r,int k){
	if(l==r) return l;
	int mid = l+r>>1;
	int temp = c[lson[Tr]]-c[lson[Tl]]+sum(right)-sum(left-1);
	if(k<=temp){
		for(int i = left-1; i; i-=i&-i) use[i]=lson[use[i]];
		for(int i = right; i; i-=i&-i) use[i]=lson[use[i]];
		return query(left,right,lson[Tl],lson[Tr],l,mid,k);
	}else{
		for(int i = left-1; i; i-=i&-i) use[i]=rson[use[i]];
		for(int i = right; i; i-=i&-i) use[i]=rson[use[i]];
		return query(left,right,rson[Tl],rson[Tr],mid+1,r,k-temp);
	}
}
int Que(int left,int right,int k){
	for(int i = left-1; i; i-=i&-i) use[i]=S[i];
	for(int i = right; i; i-=i&-i) use[i]=S[i];
	return query(left,right,T[left-1],T[right],1,m,k);
}
char op[3];
int main(){
	int tcas;
	scanf("%d",&tcas);
	while(tcas--){
		scanf("%d%d",&n,&q);
		m=tot=0;
		for(int i = 1; i <= n; i++){
			scanf("%d",&a[i]);
			t[++m]=a[i];
		}
		for(int i = 1; i <= q; i++){
			scanf("%s",op);
			p[i].f=(op[0]=='Q');
			if(p[i].f){
				scanf("%d%d%d",&p[i].l,&p[i].r,&p[i].k);
			}else{
				scanf("%d%d",&p[i].l,&p[i].r);
				t[++m]=p[i].r;
			}
		}
		sort(t+1,t+1+m);
		m=unique(t+1,t+1+m)-t-1;
		for(int i = 1; i <= n; i++) update(T[i],T[i-1],1,m,Hash(a[i]),1);
		for(int i = 1; i <= n; i++) S[i]=T[0];
		for(int i = 1; i <= q; i++){
			if(p[i].f) printf("%d\n",t[Que(p[i].l,p[i].r,p[i].k)]);
			else{
				add(p[i].l,Hash(a[p[i].l]),-1);
				add(p[i].l,Hash(p[i].r),1);
				a[p[i].l]=p[i].r;
			}
		}
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章