JZOJ-senior-1011. 【GDKOI2009模拟3】Zoo

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/HuangXinyue1017/article/details/83242494

Time Limits: 1000 ms Memory Limits: 65536 KB

Description

JZ拥有一个很大的野生动物园。这个动物园坐落在一个狭长的山谷内,这个区域从南到北被划分成N个区域,每个区域都饲养着一头狮子。这些狮子从北到南编号为1,2,3,…,N。每头狮子都有一个觅食能力值Ai,Ai越小觅食能力越强。饲养员西西决定对狮子进行M次投喂,每次投喂都选择一个区间[I,J],从中选取觅食能力值第K强的狮子进行投喂。值得注意的是,西西不愿意对某些区域进行过多的投喂,他认为这样有悖公平。因此西西的投喂区间是互不包含的(即区间[1,10]不会与[3,4]或[5,10]同时存在,但可以与[9,11]或[10,20]一起)。同一区间也只会出现一次。你的任务就是算出每次投喂后,食物被哪头狮子吃掉了。

Input

觅食能力值。(1<=能力值<=maxlongint)。此后M行,每行描述一次投喂。第t+2的三个数I,J,K表示在第t次投喂中,西西选择了区间[I,J]内觅食能力值第K强的狮子进行投喂。

Output

输出文件有M行,每行一个整数。第i行的整数表示在第i次投喂中吃到食物的狮子的觅食能力值。

Sample Input

7 2
1 5 2 6 3 7 4
1 5 3
2 7 1

Sample Output

3
2

Hint

对于100%的数据,有1<=N<=100000,1<=M<=50000。

Solution

区间第K大,标准的主席树例题
维护每个范围内数的个数,然后用 [ R ] [ L 1 ] [R]-[L-1] ,树上二分查找

Code

#include<algorithm>
#include<cstdio>

#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)
#define ll long long

using namespace std;

const int N=1e5+5,MX=2147483647;
int n,m,k,opl,opr,tot;
struct tree{int l,r,s;}tr[50*N];

void ins(int x,int l,int r,int p)
{
	if(l==r) return;
	int mid=((ll)l+(ll)r)>>1;
	if(p<=mid)
	{
		int y=tr[x].l;
		tr[++tot]=(tree){tr[y].l,tr[y].r,tr[y].s+1};
		tr[x].l=tot,ins(tr[x].l,l,mid,p);
	}
	else
	{
		int y=tr[x].r;
		tr[++tot]=(tree){tr[y].l,tr[y].r,tr[y].s+1};
		tr[x].r=tot,ins(tr[x].r,mid+1,r,p);
	}
}

void ask(int x,int y,int l,int r,int p)
{
	if(l==r) {printf("%d\n",l); return;}
	int mid=((ll)l+(ll)r)>>1;
	int lx=tr[x].l,ly=tr[y].l;
	int rx=tr[x].r,ry=tr[y].r;
	if(tr[ly].s-tr[lx].s>=p) ask(lx,ly,l,mid,p);
		else ask(rx,ry,mid+1,r,p-(tr[ly].s-tr[lx].s));
}

int main()
{
	freopen("zoo.in","r",stdin);
	freopen("zoo.out","w",stdout);
	scanf("%d%d",&n,&m),tot=n;
	fo(i,1,n)
	{
		scanf("%d",&k);
		tr[i]=(tree){tr[i-1].l,tr[i-1].r,tr[i-1].s+1};
		ins(i,1,MX,k);
	}
	fo(i,1,m)
	{
		scanf("%d%d%d",&opl,&opr,&k);
		ask(opl-1,opr,1,MX,k);
	}
}

猜你喜欢

转载自blog.csdn.net/HuangXinyue1017/article/details/83242494