[bzoj4906][BeiJing2017]喷式水战改

时间:2023-01-12 16:18:21

来自FallDream的博客,未经允许,请勿转载,谢谢。


【题目背景】
拿到了飞机的驾照(?),这样补给就不愁了
XXXX年XX月XX日
拿到了喷气机(??)的驾照,这样就飞得更快了
XXXX年XX月XX日
拿到了攻击机(???)的驾照(不存在的)
XXXX年XX月XX日
用铅版做夹层的话,机身可是会变重的呢
XXXX年XX月XX日
幸酱的特制快递,精确投递到了目标地点
-------------------------------------
又是核平的一天。
天音正在给喷气机做保养,并充填燃料。
这种喷气机是某姬(?????)特别制作的,发动机拥有三种工作状态
1、通常型(Original):在高空平飞或隐蔽飞行时进行的低功耗高效率工作状态
2、后期型(Extended):为在俯冲时最大化能量利用率而特别改造过的工作状态
3、增强型(Enhanced):在俯冲攻击结束后为产生极限扭力抬高高度的工作状态
在一次攻击中,喷气机将会经历"通常-后期-增强-通常"的工作流程
不同工作状态中,燃料的利用效率是不同的
现在天音正在调整喷气机燃料装填序列
你需要做的就是求出燃料能产生的最大总能量
为什么是你?
和平还是核平,选一个吧
 
【题目描述】
初始燃料序列为空。每次操作会向序列中的pi位置添加xi单位的同种燃料,该燃料每一单位在三种工作状态下能产生的能量分别为ai, bi, ci。添加的位置pi是指,在添加后,加入的第一个单位燃料前面有pi个单位的原燃料。全部的xi单位燃料依次放置,然后原来在pi位置的燃料(如果有的话)依次向后排列。对于一个确定的燃料序列,其能产生的最大总能量为:将序列依次分成"通常-后期-增强-通常"四段(每段可以为空),每一段在对应工作状态下产生的能量之和的最大值。对于每次添加操作,你需要给出该次操作使得最大总能量增加了多少。如果对于这种计算方式没有直观的感受,可以查看样例说明。
1 ≤ n ≤ 10^5, 1 ≤ ai, bi, ci ≤ 10^4, 1 ≤ xi ≤ 10^9
 
显然存在最优解,满足每一段都取相同的状态。
然后考虑平衡树维护,合并可以类似区间dp。
复杂度4^3*nlogn
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define MN 500005
#define getchar() (*S++)
char BB[<<],*S=BB;
using namespace std;
inline int read()
{
int x = ; char ch = getchar();
while(ch < '' || ch > '') ch = getchar();
while(ch >= '' && ch <= ''){x = x * + ch - '';ch = getchar();}
return x;
}
inline ll llread()
{
ll x = ; char ch = getchar();
while(ch < '' || ch > '')ch = getchar();
while(ch >= '' && ch <= ''){x = x * + ch - '';ch = getchar();}
return x;
}
struct data
{
ll x[][];
data(){}
data(ll a,ll b,ll c)
{
memset(x,,sizeof(x));
x[][]=x[][]=a;x[][]=b;
x[][]=c;x[][]=max(a,b);
x[][]=max(b,c);x[][]=max(a,c);
x[][]=x[][]=x[][]=max(a,max(b,c));
}
friend data operator + (data a,data b)
{
data c;memset(c.x,,sizeof(c.x));
for(int l=;l<=;++l)
for(int i=;i+l-<;++i)
{
int j=i+l-;c.x[i][j]=;
for(int k=i;k<=j;++k)
c.x[i][j]=max(c.x[i][j],a.x[i][k]+b.x[k][j]);
}
return c;
}
}s[MN+];
int fa[MN+],sz[MN+],c[MN+][],rt=,mark,A[MN+],L[MN+],B[MN+],C[MN+],n,cnt=,q[MN+],top=;
ll size[MN+],tot;
int tms=;
inline void update(int x)
{
s[x]=(data){1LL*A[x]*L[x],1LL*B[x]*L[x],1LL*C[x]*L[x]};
if(c[x][]) s[x]=s[c[x][]]+s[x];
if(c[x][]) s[x]=s[x]+s[c[x][]];
size[x]=size[c[x][]]+size[c[x][]]+L[x];
sz[x]=sz[c[x][]]+sz[c[x][]]+;
} int Find(int x,ll pos)
{
ll Sz1=size[c[x][]],Sz2=Sz1+L[x];
if((Sz1<pos||(!c[x][]&&!pos))&&Sz2>=pos) return x;
if(Sz1>=pos) return Find(c[x][],pos);
return tot+=Sz2,Find(c[x][],pos-Sz2);
} void ins(int&x,int ai,int bi,int ci,ll pos,int len,int last=)
{
if(!x)
{
x=++cnt;s[x]=data(1LL*ai*len,1LL*bi*len,1LL*ci*len);
L[x]=size[x]=len;A[x]=ai;B[x]=bi;C[x]=ci;sz[x]=;fa[x]=last;
return;
}
ll Sz=size[c[x][]]+L[x];
if(Sz<=pos) ins(c[x][],ai,bi,ci,pos-Sz,len,x);
else ins(c[x][],ai,bi,ci,pos,len,x);
update(x);
if(max(sz[c[x][]],sz[c[x][]])>0.7*sz[x]) mark=x;
} void Modify(int x,int k,ll pos,int Len)
{
if(x==k)
{
L[x]=Len;update(x);
return;
}
if(size[c[x][]]>=pos) Modify(c[x][],k,pos,Len);
else Modify(c[x][],k,pos-L[x]-size[c[x][]],Len);
update(x);
} void Dfs(int x)
{
if(c[x][]) Dfs(c[x][]);
q[++top]=x;
if(c[x][]) Dfs(c[x][]);
} void Build(int&x,int l,int r,int last)
{
if(l>r) {x=;return;}
int mid=l+r>>;x=q[mid];fa[x]=last;
Build(c[x][],l,mid-,x);
Build(c[x][],mid+,r,x);
update(x);
} void rebuild(int x)
{
mark=top=;Dfs(x);int y=fa[x];
if(!y) Build(rt,,top,);
else Build(c[y][c[y][]==x],,top,y);
} int main()
{
fread(BB,,<<,stdin);
n=read();ins(rt,,,,,);ll pre=;
for(int i=;i<=n;++i)
{
ll p=llread();
int ai=read(),bi=read(),ci=read(),x=read();
tot=tms=;int k=Find(rt,p);
if(tot+size[c[k][]]+L[k]!=p)
{
ll Left=tot+size[c[k][]]+L[k]-p;
tms=;Modify(rt,k,p,L[k]-Left);
ins(rt,ai,bi,ci,p,x);if(mark) rebuild(mark);
ins(rt,A[k],B[k],C[k],p+x,Left);
}
else ins(rt,ai,bi,ci,p,x);
printf("%lld\n",s[rt].x[][]-pre);
pre=s[rt].x[][];if(mark) rebuild(mark);
}
return ;
}