题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=6609
题目分析:
刚开始做的时候用的set+堆维护,T成SB
赛后看了题解才明白想错了思路。
转化一下,我们去想能留下几个不就好了吗…
然后用权值线段树去维护找答案
如果左子树的和比要找的大,那肯定能留下的都在左子树
反之我们把左子树都留下来,然后去右子树。
当到了叶节点,可以直接算答案,当然还要判断这个答案和本身数字的数量问题
代码:
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#define int long long
const int maxm=2e5+100;
int n,m;
int _hash[maxm],a[maxm];
struct node{
int sum,num;
}st[maxm*4];
inline void pushup(int o)
{
st[o].sum=st[(o<<1)].sum+st[(o<<1)|1].sum;
st[o].num=st[(o<<1)].num+st[(o<<1)|1].num;
}
void insert(int o,int l,int r,int ind)
{
if(l>=r)
{
st[o].sum+=_hash[l];
st[o].num++;
return;
}
int mid=(l+r)>>1;
if(ind<=mid) insert((o<<1),l,mid,ind);
else insert((o<<1)|1,mid+1,r,ind);
pushup(o);
}
int ask(int o,int l,int r,int val)
{
if(st[o].sum<=val) return st[o].num;
if(l==r) return std::min(st[o].num,val/_hash[l]);
int mid=(l+r)>>1;
if(st[(o<<1)].sum>=val) return ask((o<<1),l,mid,val);
else return ask((o<<1)|1,mid+1,r,val-st[(o<<1)].sum)+st[(o<<1)].num;
}
void work()
{
scanf("%lld%lld",&n,&m);
int t=0;
memset(st,0,sizeof(st));
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
_hash[i]=a[i];
}
std::sort(_hash+1,_hash+n+1);
t=std::unique(_hash+1,_hash+n+1)-_hash-1;
for(int i=1;i<=n;i++)
{
if(i==1) printf("0 ");
else printf("%lld ",i-1-ask(1,1,t,m-a[i]));
int w=std::lower_bound(_hash+1,_hash+t+1,a[i])-_hash;
insert(1,1,t,w);
}
puts("");
}
signed main()
{
int T;
scanf("%lld",&T);
while(T--) work();
return 0;
}