题目描述
小卡家有N只狗,由于品种、年龄不同,每一只狗都有一个不同的漂亮值。漂亮值与漂亮的程度成反比(漂亮值越低越漂亮),吃饭时,狗狗们会按顺序站成一排等着主人给食物。
可是嘉嘉真的很懒,他才不肯喂这么多狗呢,这多浪费时间啊,于是他每次就只给第i只到第j只狗中第k漂亮的狗狗喂食(好狠心的人啊)。而且为了保证某一只狗狗不会被喂太多次,他喂的每个区间(i,j)不互相包含。
输入输出格式
输入格式:
第一行输入两个数n,m,你可以假设n<300001 并且 m<50001;m表示他喂了m次。
第二行n个整数,表示第i只狗的漂亮值为ai。
接下来m行,每行3个整数i,j,k表示这次喂食喂第i到第j只狗中第k漂亮的狗的漂亮值。
输出格式:
M行,每行一个整数,表示每一次喂的那只狗漂亮值为多少。\
题解:这道题是一段区间问题,其实可以将询问保存下来,然后将询问按照起点和终点作为第一和第二关键字,排序,然后一段一段来处理,当我处理到第i段时,i段起点之前的区间就没有用了,所以就相当于求区间第k小值,用树状数组维护,用二分寻找答案。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int a[300010];//点的个数
struct node
{
int x,y,k,d;//x→y第k小,d:原编号
} q[51000];//询问
int ans[51000];//存结果
int i,j,n,m;
int t[301000];//树状数组
int h[301000];
bool cmp(node aa,node bb)//关键字1:左端 关键字2:右端
{
if (aa.x==bb.x) return aa.y<bb.y;
return aa.x<bb.x;
}
void xg(int k,int p)//树状数组之
{
while (k<=n)
{
t[k]+=p;
k+= k & -k;
}
}
int qh(int k)
{
int sum=0;
while (k>=1)
{
sum+=t[k];
k-= k & -k;
}
return sum;
}
int main()
{
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++)
{
scanf("%d",&a[i]);
h[i]=a[i];
}
sort(h+1,h+n+1);//h:排好序的数组
for (i=1;i<=m;i++)
{
scanf("%d%d%d",&q[i].x,&q[i].y,&q[i].k);
q[i].d=i;
}
int he=1;int ta=0;
sort(q+1,q+m+1,cmp);//排序
for (i=1;i<=m;i++)
{
while (ta<q[i].y)//把之前没有加过的元素加到树状数组中
{
ta++;
xg(lower_bound(h+1,h+n+1,a[ta])-h,1);//同下
}
while (he<q[i].x)//删去前面加过的元素
{
xg(lower_bound(h+1,h+n+1,a[he])-h,-1);
he++;
}
int l=1;
int r=n;
int mid;
while (l<r)//二分找第k小数
{
mid=(l+r)>>1;
if (qh(mid)>=q[i].k) r=mid; else l=mid+1;
}
ans[q[i].d]=h[l];
}
for (i=1;i<=m;i++) printf("%d\n",ans[i]);
return 0;
}