题解思路:对于每个位置,求出需要减掉的数 然后在权值线段树上进行二分找答案。
#include<bits/stdc++.h> using namespace std; #define maxn 200005 #define ll long long #define ls l,mid,rt<<1 #define rs mid+1,r,rt<<1|1 typedef pair<int,int> PII; const int mod = 1e9+7; int n,m; ll a[maxn],b[maxn],num[maxn<<2],sum[maxn<<2],atag[maxn<<2]; void Pushup(int rt){ sum[rt]=sum[rt<<1]+sum[rt<<1|1]; num[rt]=num[rt<<1]+num[rt<<1|1]; } void Build(int l,int r,int rt){ num[rt]=sum[rt]=0; if(l==r)return ; int mid=(l+r)>>1; Build(ls); Build(rs); } void Update(int l,int r,int rt,int pos){ if(l==r&&l==pos){ sum[rt]+=b[pos]; num[rt]++; return ; } int mid=(l+r)>>1; if(pos<=mid)Update(ls,pos); else Update(rs,pos); Pushup(rt); } int Query(int l,int r,int rt,ll ss){ if(l==r){ int ans=ss/b[l]; if(ss%b[l])ans++; return ans; } int mid=(l+r)>>1; if(sum[rt<<1|1]>=ss)return Query(rs,ss); else{ int ans=num[rt<<1|1]; ans+=Query(ls,ss-sum[rt<<1|1]); return ans; } } int main() { int t;cin>>t; while(t--){ scanf("%d %d",&n,&m); for(int i=1;i<=n;i++){ scanf("%lld",&a[i]); b[i]=a[i]; } sort(b+1,b+n+1); int nn=unique(b+1,b+n+1)-(b+1); Build(1,nn,1); ll Sum=0; for(int i=1;i<=n;i++){ Sum+=a[i]; if(Sum<=m){ printf("0 "); int pos=lower_bound(b+1,b+nn+1,a[i])-b; Update(1,nn,1,pos); } else{ ll ss=Sum-m; printf("%d ",Query(1,nn,1,ss)); int pos=lower_bound(b+1,b+nn+1,a[i])-b; Update(1,nn,1,pos); } } printf(" "); } }