Description
小沐拥有一个很大的野生动物园。这个动物园坐落在一个狭长的山谷内,这个区域从西到东被划分成N个区域,每个区域都饲养着一头狮子。这些狮子从西到东编号为1,2,3,…,N。每头狮子都有一个觅食能力值Ai,Ai越小觅食能力越强。
小沐决定对狮子进行M次投喂,每次投喂都选择一个区间[I,J],从中选取觅食能力值第K强(这里的第K强是指把A[I]...A[J]由小到大排序后的第K个)的狮子进行投喂。值得注意的是,小沐不愿意对某些区域进行过多的投喂,他认为这样有悖公平。因此小沐的投喂区间是互不包含的。你的任务就是算出每次投喂后,食物被哪头狮子吃掉了。
Input
输入第一行有两个数N和M。此后一行有N个数,从南到北描述狮子的觅食能力值。此后M行,每行描述一次投喂。第t+2的三个数I,J,K表示在第t次投喂中,小沐选择了区间[I,J]内觅食能力值第K强的狮子进行投喂。
Output
小沐拥有一个很大的野生动物园。这个动物园坐落在一个狭长的山谷内,这个区域从西到东被划分成N个区域,每个区域都饲养着一头狮子。这些狮子从西到东编号为1,2,3,…,N。每头狮子都有一个觅食能力值Ai,Ai越小觅食能力越强。
小沐决定对狮子进行M次投喂,每次投喂都选择一个区间[I,J],从中选取觅食能力值第K强(这里的第K强是指把A[I]...A[J]由小到大排序后的第K个)的狮子进行投喂。值得注意的是,小沐不愿意对某些区域进行过多的投喂,他认为这样有悖公平。因此小沐的投喂区间是互不包含的。你的任务就是算出每次投喂后,食物被哪头狮子吃掉了。
Input
输入第一行有两个数N和M。此后一行有N个数,从南到北描述狮子的觅食能力值。此后M行,每行描述一次投喂。第t+2的三个数I,J,K表示在第t次投喂中,小沐选择了区间[I,J]内觅食能力值第K强的狮子进行投喂。
Output
输出有M行,每行一个整数。第i行的整数表示在第i次投喂中吃到食物的狮子的觅食能力值。
分析:
这个题等于是给定n个数,然后给m次询问,问i-j号数的第k小值。一看到区间查找(其实是因为正在学线段树)就想到用线段树。
用离线算法,把所有的查询存起来,然后按照左端点从小到大排序。因为每个查询用到的是A[i-j],而一般的线段树维护集合查询第K小数难以在规定区间[i-j]同时查询,所以必须把A[1]-A[i-1]删掉,A[i]-A[j]加入,又因为是按照左端点排序的,所以不用担心j右边。注意A数组需要先离散化为B数组。
枚举到一个查询时,把A[i]之前的数字删掉,A[i-j]的数字添加进集合,然后查询,记录答案即可。最后再按照输入顺序排序,输出答案。
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100005;
const int maxm=50005;
int n,m,np=0,rt=0,tot=0,lc[maxn*2],rc[maxn*2],num[maxn*2],B[maxn],A[maxn];
struct data{int i,j,k,id,ans;}kk[maxm];
bool cmp1(data a,data b) {return a.i<b.i;}
bool cmp2(data a,data b) {return a.id<b.id;}
void ready()
{
for(int i=1;i<=n;i++)
{
scanf("%d",&A[i]);
B[++tot]=A[i];
}
sort(B+1,B+1+tot);
tot=unique(B+1,B+1+tot)-B-1;
for(int t=1;t<=m;t++)
{
scanf("%d%d%d",&kk[t].i,&kk[t].j,&kk[t].k);
kk[t].id=t;
}
sort(kk+1,kk+1+m,cmp1);
}
void pushup(int now,int L,int R)
{
num[now]=num[L]+num[R];
}
void Build(int &now,int L,int R)
{
now=++np;
if(L==R) return;
int m=(L+R)/2;
Build(lc[now],L,m);
Build(rc[now],m+1,R);
}
void Update(int now,int L,int R,int x,int d)
{
if(L==R)
{
num[now]+=d;
return;
}
int m=(L+R)/2;
if(x<=m) Update(lc[now],L,m,x,d);
else Update(rc[now],m+1,R,x,d);
pushup(now,lc[now],rc[now]);
}
int Kth(int now,int L,int R,int x)
{
if(L==R) return L;
int m=(L+R)/2,t=num[lc[now]];
if(x<=t) return Kth(lc[now],L,m,x);
return Kth(rc[now],m+1,R,x-t);
}
int main()
{
// freopen("in.txt","r",stdin);
scanf("%d%d",&n,&m);
ready();//离散化
Build(rt,1,tot);
int x=1,y=1;
for(int t=1;t<=m;t++)
{
for(;x<kk[t].i;x++)//A[1]-A[i-1] 删掉
{
int v=lower_bound(B+1,B+1+tot,A[x])-B;
Update(rt,1,tot,v,-1);
}
for(;y<=kk[t].j;y++)//A[i]-A[j]加入
{
int v=lower_bound(B+1,B+1+tot,A[y])-B;
Update(rt,1,tot,v,1);
}
kk[t].ans=Kth(rt,1,tot,kk[t].k);
}
sort(kk+1,kk+1+m,cmp2);//按照输入顺序排序
for(int i=1;i<=m;i++) printf("%d\n",B[kk[i].ans]);
return 0;
}