1. 程式人生 > 實用技巧 >整體二分求區間第k大

整體二分求區間第k大

#include<stdio.h>
#define inf 0x3f3f3f3f
int s[200100];
void add(int x,int y){
	for(int i=x;i<=200000;i=i+(i&(-i))){
		s[i]+=y;
	}
}
int sum(int x){
	int ans=0;
	for(int i=x;i>0;i=i-(i&(-i))){
		ans=ans+s[i];
	}
	return ans;
}
int ans[200100];
struct node{
	int x,y,id,k,type;
}a[400100],w[400100],e[400100];
void solve(int cs,int zd,int l,int r){
	if(cs>zd||l>r)return ;
	if(l==r){
		for(int i=cs;i<=zd;i++){
			if(a[i].type==2){
				ans[a[i].id]=l;
			}
		}
		return ;
	}
	int m=(l+r)/2;
	int t0=0,t1=0;
	for(int i=cs;i<=zd;i++){
		if(a[i].type==1){
			if(a[i].x<=m){
				add(a[i].id,1);
				w[++t0]=a[i];
			}
			else{
				e[++t1]=a[i];
			}
		}
		else{
			int now=sum(a[i].y)-sum(a[i].x-1);
			if(now>=a[i].k){
				w[++t0]=a[i];
			}
			else{
				a[i].k-=now;
				e[++t1]=a[i];
			}
		}
	}
	for(int i=1;i<=t0;i++){
		a[cs+i-1]=w[i];
	}
	for(int i=1;i<=t1;i++){
		a[cs+t0+i-1]=e[i];
	}
	for(int i=cs;i<=zd;i++){
		if(a[i].type==1&&a[i].x<=m){
			add(a[i].id,-1);
		}
	}
	solve(cs,cs+t0-1,l,m);
	solve(cs+t0,cs+t0+t1-1,m+1,r);
}
int main(){
	int cnt=0;
	int n,m;
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++){
		int temp;
		scanf("%d",&temp);
		a[++cnt]=(node){temp,0,i,0,1};
	}
	for(int i=1;i<=m;i++){
		int l,r,z;
		scanf("%d %d %d",&l,&r,&z);
		a[++cnt]=(node){l,r,i,z,2};
	}
	solve(1,cnt,-inf,inf);
	for(int i=1;i<=m;i++){
		printf("%d\n",ans[i]);
	}
}