Problem A:野生动物园 Time Limit:30000MS Memory Limit:65536K Description 有一个很大的野生动物园。这个动物园坐落在一个狭长的山谷内,这个区域从南到北被划分成N个区域,每个区域都饲养着一头狮子。这些狮子从北到南编号为1,2,3,…,N。每头狮子都有一个觅食能力值Ai,Ai越小觅食能力越强。饲养员cmdButtons决定对狮子进行M次投喂,每次投喂都选择一个区间[I,J],从中选取觅食能力值第K强的狮子进行投喂。值得注意的是,cmdButtons不愿意对某些区域进行过多的投喂,他认为这样有悖公平。因此cmdButtons的投喂区间是互不包含的。你的任务就是算出每次投喂后,食物被哪头狮子吃掉了。 Input 输入文件第一行有两个数N和M。此后一行有N个数,从南到北描述狮子的觅食能力值。此后M行,每行描述一次投喂。第t+2的三个数I,J,K表示在第t次投喂中,cmdButtons选择了区间[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
数据范围:
对于50%的数据,有1<=N<=10000,1<=M<=500;
对于100%的数据,有1<=N<=100000,1<=M<=50000。
|
[Submit] [Go Back] [Status] [Clarify]
线段树,
构建N个线段树,维护 其使第i个线段树表示加元素,从1加到i时,a[i]在每条线段[l,r]中为第几大,
这样可以快速求得区间第k大
由于范围较大,可以使用可持久化数据结构,不必完整的构建N个线段树,中间未更新的节点不必重新建造
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
struct node
{
int l,r,len;
}t[5000010];
int n,m,N;
int a[100010],b[100010],root[100010];
int build (int l,int r)
{
int i=++N;
if (l!=r)
{
int mid=(l+r)>>1;
t[i].l=build( l ,mid );
t[i].r=build( mid+1,r);
}
return i;
}
int change(int i, int l, int r ,int k )
{
++N; t[N]=t[i]; i=N;
t[i].len++;
if (l!=r)
{
int mid=(l+r)>>1;
if (k<=mid) t[i].l=change(t[i].l, l, mid, k);
else
t[i].r=change(t[i].r, mid+1, r, k);
}
return i;
}
int query(int i1,int i2,int l,int r ,int k)
{
if (l==r) return l;
else
{
int mid=(l+r) >>1;
if ( k<= t[ t[i1].l].len - t[ t[i2].l].len ) return query( t[i1].l, t[i2].l, l, mid, k);
else
return query( t[i1].r, t[i2].r, mid+1, r, k-( t[ t[i1].l ].len- t[t[i2].l].len ) );
}
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1; i<=n; i++)
scanf("%d",&a[i]);
memcpy(b,a,sizeof(a));
sort(b+1,b+1+n);
N=1;
for (int i=2; i<=n; i++)
if (b[i]!=b[i-1] ) b[++N]=b[i];
root[0]=build(1,n);
for (int i=1; i<=n; i++)
root[i]=change(root[i-1],1,n,upper_bound(b+1,b+1+n,a[i])-(b+1) );
for (int i=1; i<=m; i++)
{
int x,y,k;
scanf("%d%d%d",&x,&y,&k);
printf("%d\n",b[ query( root[y],root[x-1] ,1, n, k ) ] );
}
return 0;
}