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;
}

 

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