题解:P11678 [USACO25JAN] Watering the Plants P
更多凸性优化
令
定义
使用后缀
我们将
-
j\le c_i$,有:$f_i(j)=g_{i-1}(c_i-j)+j\times w_i -
j>c_i$,有:$f_i(j)=g_{i-1}(0)+j\times w_i
由于
还是分开来看:
做完之后,全部推成后缀
我们考虑维护点到点斜率,注意,此处的斜率其实相当于
观察转移式,我们要求的答案是
具体的,我们令
维护斜率可以用平衡树,操作有【区间翻转】、【区间取反(翻转后斜率都取反)】、【覆盖成
然后就可以了,时间复杂度
#include <iostream>
#include <cstring>
#include <algorithm>
#include <random>
#include <ctime>
using namespace std;
typedef long long ll;
const int N=500010,M=1000010;
const ll INF=1e18;
int n;
int c[N],w[N];
int mx;
void Min(ll &x,ll y) { x=min(x,y); }
namespace FHQ
{
mt19937 rnd(time(0));
ll val[M],sum[M],add[M];
int pri[M],ch[M][2],sz[M],rev[M],mul[M],idx,root;
inline int new_node(int v)
{
int u=++idx;
val[u]=sum[u]=v;
pri[u]=rnd();
sz[u]=1;
mul[u]=1;
return u;
}
inline void pushup(int u)
{
sz[u]=sz[ch[u][0]]+sz[ch[u][1]]+1;
sum[u]=sum[ch[u][0]]+sum[ch[u][1]]+val[u];
}
inline void Rev(int u)
{
if (!u) return;
rev[u]^=1;
swap(ch[u][0],ch[u][1]);
}
inline void Mul(int u,int x)
{
if (!u) return;
mul[u]*=x;
add[u]*=x;
val[u]*=x;
sum[u]*=x;
}
inline void Add(int u,int d)
{
if (!u) return;
add[u]+=d;
val[u]+=d;
sum[u]+=(ll)d*sz[u];
}
inline void pushdown(int u)
{
if (rev[u])
{
Rev(ch[u][0]);
Rev(ch[u][1]);
rev[u]=0;
}
if (mul[u]!=1)
{
Mul(ch[u][0],mul[u]);
Mul(ch[u][1],mul[u]);
mul[u]=1;
}
if (add[u])
{
Add(ch[u][0],add[u]);
Add(ch[u][1],add[u]);
add[u]=0;
}
}
void split(int rt,int k,int &rt1,int &rt2)
{
if (!rt)
{
rt1=rt2=0;
return;
}
pushdown(rt);
if (sz[ch[rt][0]]+1<=k)
{
rt1=rt;
split(ch[rt][1],k-sz[ch[rt][0]]-1,ch[rt][1],rt2);
}
else
{
rt2=rt;
split(ch[rt][0],k,rt1,ch[rt][0]);
}
pushup(rt);
}
int merge(int rt1,int rt2)
{
if (!rt1 || !rt2) return rt1^rt2;
if (pri[rt1]<pri[rt2])
{
pushdown(rt1);
ch[rt1][1]=merge(ch[rt1][1],rt2);
pushup(rt1);
return rt1;
}
else
{
pushdown(rt2);
ch[rt2][0]=merge(rt1,ch[rt2][0]);
pushup(rt2);
return rt2;
}
}
inline void Insert(int v) { root=merge(root,new_node(v)); }
ll qrys(int u,int k)
{
if (!u) return 0;
pushdown(u);
if (sz[ch[u][0]]+1<=k) return sum[ch[u][0]]+val[u]+qrys(ch[u][1],k-sz[ch[u][0]]-1);
else return qrys(ch[u][0],k);
}
ll mdf(int u)
{
if (!u) return 0;
pushdown(u);
if (val[u]<0)
{
ll res=sum[ch[u][0]]+val[u]+mdf(ch[u][1]);
Mul(ch[u][0],0),val[u]=0;
pushup(u);
return res;
}
else
{
ll res=mdf(ch[u][0]);
pushup(u);
return res;
}
}
void adj(int rt=root)
{
pushdown(rt);
if (ch[rt][0]) adj(ch[rt][0]);
if (ch[rt][1]) adj(ch[rt][1]);
pushup(rt);
}
void print(int rt=root)
{
if (ch[rt][0]) print(ch[rt][0]);
cout << val[rt] << " ";
if (ch[rt][1]) print(ch[rt][1]);
}
void prt(int rt=root) { adj(rt);print(rt);cout << "\n---\n"; }
}
using namespace FHQ;
ll f0;
ll st;
inline ll calc(int k)
{
ll res=st+f0+qrys(root,k);
return res;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin >> n;
for (int i=1;i<=n;i++)
{
cin >> c[i];
mx=max(mx,c[i]);
}
for (int i=1;i<n;i++) cin >> w[i];
for (int i=1;i<=c[1];i++) Insert(0);
for (int i=c[1]+1;i<=mx;i++) Insert(w[1]);
f0=(ll)c[1]*w[1];
for (int i=2;i<=n;i++)
{
st=mdf(root);
f0=calc(c[i]);
cout << f0 << "\n";
int x,y;
split(root,c[i],x,y);
Rev(x);Mul(x,-1);Mul(y,0);
root=merge(x,y);
Add(root,w[i]);
}
return 0;
}