洛谷 1533 可怜的狗狗

题目描述

小卡家有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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值