小路绫只会做料理 (ayaya)(树状数组 二分)

题目描述
小路绫 (Komichi Aya) 想要给阳子 (Inokuma Youko) 做便当。

小路绫现在有n种食材,编号从1到n,她会按编号顺序放入这n种食材。

对于每种食材阳子有一个美味度ai。

小路绫知道,对于所有1≤i≤n,设前i种食材的美味度总和。在这里插入图片描述

当加入第i种食材时,如果si>m,阳子就会吃撑。

所以小路绫每放入一种食材时,都会想知道:最少要从之前已经选过的食材中去掉多少食材,才不会让阳子吃撑。

当然,小路绫不会真正地把食材去掉,她只是想知道结果而已。才不是关心你呢!

输入
第一行为两个正整数n,m,分别表示食材的种类数以及会使阳子吃撑的值m。

接下来为一行n个正整数,其中第i个正整数表示ai。
输出
输出一行n个非负整数,其中第i个非负整数表示在加入第i种食材时,至少要去掉之前加入的多少种食材才能不让阳子吃撑。

样例输入
【样例1】
7 15
1 2 3 4 5 6 7
【样例2】
5 100
80 40 40 40 60

样例输出
【样例1】
0 0 0 0 0 2 3
【样例2】
0 1 1 2 3

提示
在这里插入图片描述
思路
树状数组维护[1,i-1]区间内前k小的值的和sk,每次询问二分找最大k值使得sk+当前值<=m,i-k-1即为答案

代码实现

#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
#define re register
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=1e6+5;
const int M=5e6+5;
const int INF=0x3f3f3f3f;
const ll LINF=1e18;
const ull sed=31;
const ll mod=1e9+7;
// const double eps=1e-6;
// const double PI=acos(-1.0);
// const double delta=0.993;
typedef pair<int,int>P;
typedef pair<double,double>Pd;
typedef pair<ll,int> plt;
typedef pair<ll,ll> pll;

template<class T>inline void read(T &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch<'0'||ch>'9') {f|=(ch=='-');ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x=f?-x:x;
    return;
}

template<class T>inline void write(T x)
{
    if (x < 0) x = ~x + 1, putchar('-');
    if (x > 9) write(x / 10);
    putchar(x % 10 + '0');
}

struct node
{
    int id,val,rk;
}E[N];

ll T1[N],T2[N];
int n,m;

inline int lowbit(int x) {return x&(-x);}

void add(int x,ll p)
{
    for(;x<=n;x+=lowbit(x)) 
    {
        T1[x]+=p;
        T2[x]++;
    }
}

int sum(int x)
{
    int tot=0;
    for(;x;x-=lowbit(x)) tot+=T2[x];
    return tot; 
}

ll query(int x)
{
    ll tot=0;
    for(;x;x-=lowbit(x)) tot+=T1[x];
    return tot; 
}

bool cmp1(node a,node b)
{
    return a.val<b.val;
}

bool cmp2(node a,node b)
{
    return a.id<b.id;
}

int main() 
{
    // freopen("a.txt","r",stdin);
    read(n);read(m);
    for(int i=1;i<=n;i++)
    {
        read(E[i].val);
        E[i].id=i;
    }
    sort(E+1,E+1+n,cmp1);
    for(int i=1;i<=n;i++) E[i].rk=i;
    sort(E+1,E+1+n,cmp2);
    for(int i=1;i<=n;i++)
    {
        if(i-1) putchar(' ');
        int l=1,r=n,ans=0;
        while (l<=r)
        {
            int mid=(l+r)>>1;
            if(query(mid)+E[i].val<=m)
            {
                ans=max(ans,mid);
                l=mid+1;
            }
            else r=mid-1;
        }
        printf("%d",i-sum(ans)-1);
        add(E[i].rk,E[i].val);
    }
    puts("");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值