分析

正面想每个人能喝多少有点困难,但是可以从另一个方面想一杯茶能给多少人喝就做出来了。

不难理解,固定 $l$,$l$ 到 $r$ 的人喝的总量随着 $r$ 的增大而增大。

于是我们可以二分一杯茶可以提供给多少人喝,剩下的加到后面第一个没喝到的人头上。

要用前缀和和差分优化时间复杂度。

总体复杂度 $O(n\log{n})$,详情见代码注释。

代码

#include<iostream>
#define int long long
using namespace std;
int a[500005],s[500005],n,T,d[500005],f[500005],ans[500005];
signed main()
{
    scanf("%lld",&T);
    while(T--)
    {
        
        scanf("%lld",&n);
        for(int i=1;i<=n;i++)scanf("%lld",&a[i]),f[i]=ans[i]=0;
        for(int i=1;i<=n;i++)scanf("%lld",&s[i]);
        for(int i=1;i<=n;i++)d[i]=d[i-1]+s[i];//前缀和优化
        for(int i=1;i<=n;i++)
        {
            int l=i,r=n,mid,cnt=-1;//二分主体
            while(l<=r)
            {
                mid=(l+r)>>1;
                if(d[mid]-d[i-1]<=a[i])
                {
                    l=mid+1;
                    cnt=mid;
                }
                else r=mid-1;
            }
            if(cnt!=-1)//记得特判一个人也不够
            {
                f[i]++;
                f[cnt+1]--;//差分优化
                ans[cnt+1]+=a[i]-d[cnt]+d[i-1];
            }
            else ans[i]+=a[i];
        }
        for(int i=1;i<=n;i++)f[i]+=f[i-1];//输出
        for(int i=1;i<=n;i++)printf("%lld ",ans[i]+f[i]*s[i]);
        puts("");
    }
}