https://nanti.jisuanke.com/t/41306
抄写自https://www.cnblogs.com/xiaobuxie/p/11466214.html
首先很容易观察得到对于特定x,答案就是min{1<=i<=n} ( max(t[i]+y,max_{j>i}(t[j]+(n-j+1)*x)) ),我们可以观察得到f(i)=t[i]+y是随i递增的,g(i)=max_{j>i}(t[j]+(n-j+1)*x)是不增加的 (因为前面的人可能会因为t[i]间隔太小而使得后面的人来了以后要等待才能用洗衣机)
我们要求的答案是这两个函数的较大的那个的最小值,那么我们可以得知这个最小值再他们函数图像的低谷找到极小值
然后思考当x=0的时候,那肯定就所有人用洗衣机了因为直接光速洗完,x=y的时候,那肯定低谷就在x=y,因为用不用是一样的
所以我们把x从大到小枚举,并记录p表示取到极小值的位置,那么这个p肯定是不断左移的,因为随着x减小,g(i)曲线整体在下降,与f(i)的交点也逐渐左移
剩下就是判断是否左移,只需用李超线段树维护所有线段取最大值就行了
解释一下边界情况,t[0]=-y,但是直线只需要记录1-n就行了。因为我们比较的是t[p-1]+y和g(p)的大小,如果p=1位分界点,那么就是说从所有的都用洗衣机不手洗,所有要让t[0]+y=0,然后才能直接得到所有用洗衣机的时间max(0,t[1]+(n-1)*x)的
很多其他题解硬是要把线段树从0这个地方建起,没有必要,误导了我半天
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=1e6+10;
int n,y,now,cnt;
ll t[maxl],ans[maxl];
struct node
{
int l,r,id;
}tr[maxl<<2];
struct line
{
ll k,b;
}a[maxl];
inline void build(int k,int l,int r)
{
tr[k].l=l;tr[k].r=r;tr[k].id=n;
if(l==r)
return ;
int mid=(l+r)>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
inline void prework()
{
for(int i=1;i<=n;i++)
ans[i]=0;
build(1,1,y);
t[0]=-y;
for(int i=1;i<=n;i++)
scanf("%lld",&t[i]);
sort(t+1,t+1+n);
for(int i=1;i<=n;i++)
a[i]=line{n-i+1,t[i]};
}
inline ll fun(int id,int x){return a[id].k*x+a[id].b;}
inline void upd(int k,int id)
{
if(tr[k].l==tr[k].r)
{
if(fun(id,tr[k].l)>fun(tr[k].id,tr[k].l))
tr[k].id=id;
return;
}
int mid=(tr[k].l+tr[k].r)>>1;
if(a[tr[k].id].k<a[id].k)
{
if(fun(id,mid)>fun(tr[k].id,mid))
{
upd(k<<1,tr[k].id);
tr[k].id=id;
}
else upd(k<<1|1,id);
}
if(a[tr[k].id].k>a[id].k)
{
if(fun(id,mid)>fun(tr[k].id,mid))
{
upd(k<<1|1,tr[k].id);
tr[k].id=id;
}
else upd(k<<1,id);
}
}
inline ll qry(int k,int x)
{
if(tr[k].l==tr[k].r)
return fun(tr[k].id,x);
int mid=(tr[k].l+tr[k].r)>>1;
if(x<=mid)
return max(fun(tr[k].id,x),qry(k<<1,x));
else
return max(fun(tr[k].id,x),qry(k<<1|1,x));
}
inline ll f(int i){return t[i-1]+y;}
inline ll g(int i,int x){return qry(1,x);}
inline void mainwork()
{
int p=n;
for(int x=y;x>=1;x--)
{
ll cur=max(f(p),g(p,x));
ll res=g(p,x);
while(p>=2 && max(f(p-1),max(res,fun(p-1,x)))<=cur)
{
cur=max(f(p-1),max(res,fun(p-1,x)));
--p;
upd(1,p);
res=max(res,fun(p,x));
}
ans[x]=cur;
}
}
inline void print()
{
for(int i=1;i<=y;i++)
printf("%lld%c",ans[i]," \n"[i==y]);
}
int main()
{
while(~scanf("%d%d",&n,&y))
{
prework();
mainwork();
print();
}
return 0;
}