[主席樹]hdu2665 區間第k大

Input
The first line is the number of the test cases.
For each test case, the first line contain two integer n and m (n, m <= 100000), indicates the number of integers in the sequence and the number of the quaere.
The second line contains n integers, describe the sequence.
Each of following m lines contains three integers s, t, k.
[s, t] indicates the interval and k indicates the kth big number in interval [s, t]


Output
For each test case, output m lines. Each line contains the kth big number.


Sample Input
1
10 1
1 4 2 3 5 6 7 8 9 0
1 3 2


Sample Output

2

【題意】

t組樣例,有n個數,m個詢問。

m個詢問中有l,r,k;

詢問在[l,r]區間中,第k大的數是多少。

【解法】

將n個數離散化(假設離散化後下標爲1-t)後建立一顆區間爲1-t的線段樹,每個[x,x]都表示離散化後下標爲x的數的個數。

用主席數記錄每加入一個數後該線段樹的變化。

最後求[l,r]區間的第k大時

兩顆差值樹中  左子樹的size表示比當前根小的數的個數,如果左子樹size>=k就在左子樹中找,否則就去右子樹中找k-左子樹size的值。。。。。

呃,感覺解釋不清。。意會意會吧。。上代碼了。。

 

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#define N 100005
using namespace std;
int tree[N*25],lchild[N*25],rchild[N*25],root[N];
int a[N],b[N],cnt;
map<int,int>mp;
void build(int l,int r,int root){
	if(l==r){
		tree[root]=0;
		return;
	}
	int mid=l+r>>1;
	build(l,mid,lchild[root]=++cnt);
	build(mid+1,r,rchild[root]=++cnt);
	tree[root]=tree[lchild[root]]+tree[rchild[root]];
	return ;
}
void update(int last,int cur,int l,int r,int x){
	tree[cur]=tree[last];
	lchild[cur]=lchild[last];
	rchild[cur]=rchild[last];
	if(l==r){
		tree[cur]++;
		return;
	}
	int mid=l+r>>1;
	if(x<=mid)	update(lchild[last],lchild[cur]=++cnt,l,mid,x);
	else update(rchild[last],rchild[cur]=++cnt,mid+1,r,x);
	tree[cur]=tree[lchild[cur]]+tree[rchild[cur]];
	return ;
}
int query(int last,int cur,int l,int r,int k){
	if(l==r){
		//printf("l=%d r=%d k=%d\n",l,r,k);
		return l;
	}
	int mid=l+r>>1;
	int now=tree[lchild[cur]]-tree[lchild[last]];//注意判斷的是左子樹的size哦 
//	printf("left=%d mid=%d right=%d now=%d k=%d\n",l,mid,r,now,k);
	if(now>=k)	return query(lchild[last],lchild[cur],l,mid,k);
	else return query(rchild[last],rchild[cur],mid+1,r,k-now);
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		cnt=0;
		mp.clear();//??? 
		int n,m,ss=0;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
			b[i]=a[i];
		}
		sort(b+1,b+n+1);
	/*	for(int i=1;i<=n;i++){
			if(i!=n)	printf("b[%d]=%d ",i,b[i]);
			else printf("b[%d]=%d\n",i,b[i]);
		}
		*/
		int t=unique(b+1,b+1+n)-b-1;//離散化 
		//printf("t=%d\n",t);
		build(1,t,++cnt);
		root[0]=1; 
		for(int i=1;i<=t;i++){
			mp[b[i]]=i;
		}
		for(int i=1;i<=n;i++){
			root[i]=++cnt;
			update(root[i-1],root[i],1,t,mp[a[i]]);
		}
		while(m--){
			int left,right,k;
			scanf("%d%d%d",&left,&right,&k);
			printf("%d\n",b[query(root[left-1],root[right],1,t,k)]);//query返回的是第k大的數離散化後的下標,所以b[query]纔是原來的值 
		}
	}
	return 0;
} 

 

 

 

 

 

 

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