模板—算法—整体二分(区间k小值)

模板—算法—整体二分(区间k小值)

Code:

#include <cstdio>
#include <algorithm>
using namespace std;
#define N 200010
int num[N],number[N],tmp[N],ans[N],n,m,id[N];
struct Ask {int l,r,id,k;}ask[N],ask1[N],ask2[N];
void change(int x,int y) {while(x<=n) tmp[x]+=y,x+=x&-x;}
int find(int x) {int sum=0;while(x) sum+=tmp[x],x-=x&-x;return sum;}
bool cmp(const int &a,const int &b) {return num[a]<num[b];}
int find_ord(int x)
{
	int l=1,r=n+1;
	while(l<r)
	{
		int mid=(l+r)>>1;
		if(number[mid]>=x) r=mid;
		else l=mid+1;
	} return l;
}
void solve(int l,int r,int tl,int tr)
{
	if(l==r) {for(int i=tl;i<=tr;i++) ans[ask[i].id]=number[l]/*,printf("%d %d\n",ask[i].id,l)*/;return;}
	for(int i=l;i<=(l+r)>>1;i++) change(id[i],1); int top1=0,top2=0;
	for(int i=tl;i<=tr;i++)
		if(find(ask[i].r)-find(ask[i].l-1)>=ask[i].k) ask1[++top1]=ask[i];
		else ask2[++top2]=ask[i],ask2[top2].k-=find(ask[i].r)-find(ask[i].l-1);
	for(int i=1;i<=top1;i++) ask[tl+i-1]=ask1[i];
	for(int i=1;i<=top2;i++) ask[tl+top1+i-1]=ask2[i];
	for(int i=l;i<=(l+r)>>1;i++) change(id[i],-1);
	solve(l,(l+r)>>1,tl,tl+top1-1),solve(((l+r)>>1)+1,r,tl+top1,tr);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&num[i]),number[i]=num[i],id[i]=i;
	sort(number+1,number+n+1),sort(id+1,id+n+1,cmp);
	for(int i=1;i<=n;i++) num[i]=find(num[i]);
	for(int i=1;i<=m;i++) scanf("%d%d%d",&ask[i].l,&ask[i].r,&ask[i].k),ask[i].id=i;
	solve(1,n,1,m);
	for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
}

  

posted @ 2019-04-04 20:23  Yang1208  阅读(207)  评论(0编辑  收藏  举报