首先看到要插入序列,所以自然地想到平衡树,那么左儿子就是左边的序列,右儿子就是右边的序列,求这个值的朴素算法是dp吧,就是前 \(i\) 个燃料,已经到了第 \(j\) 阶段的最大值,但是因为左右儿子是一坨序列,我如果按照这样维护 \(dp\) 的话我也不知道右儿子开始的时候到了哪个阶段,所以很自然地想到区间dp,就是把状态改成这个 \(f_{p,l,r}\) 表示节点 \(p\) 的子树所对应的区间完成了 \(l,r\) 这个阶段所能获得的最大值,每次pushup的时候合并一下左右两个区间即可,我实现使用的是fhq
code:
#include <bits/stdc++.h>
#define int long long
#define ull unsigned long long
#pragma GCC optimeze(3)
#pragma GCC optimeze(2)
#define PII pair<int, int>
#define pb push_back
#define fi first
#define se second
#define lowbit(x) (x & (-x))
#define inv(x) (qpow(x,mod-2))
using namespace std;
const int N=4e5+10;
double eps=1e-6;
inline int read(){char ch=getchar();bool f=0;int x=0;for(;!isdigit(ch);ch=getchar())if(ch=='-')f=1;for(;isdigit(ch);ch=getchar())x=(x<<1)+(x<<3)+(ch^48);if(f==1)x=-x;return x;
}
struct node{int ls,rs,w,siz,a[4],len,al;int f[5][5];
}tr[N];
int tot,n,root;
void newnode(int&id,int k,int a,int b,int c){id=++tot;tr[id].w=rand(),tr[id].siz=1,tr[id].al=tr[id].len=k;tr[id].a[1]=a,tr[id].a[2]=b,tr[id].a[3]=c;tr[id].f[1][1]=tr[id].a[1]*k;tr[id].f[2][2]=tr[id].a[2]*k;tr[id].f[3][3]=tr[id].a[3]*k;tr[id].f[4][4]=tr[id].a[1]*k;for(int i=1;i<=3;i++){for(int j=i+1;j<=4;j++){tr[id].f[i][j]=max(tr[id].f[i][j-1],tr[id].f[j][j]);}}
}
void pushup(int p){memset(tr[p].f,0,sizeof tr[p].f);int ok[5]={};int ls=tr[p].ls,rs=tr[p].rs;ok[1]=tr[p].f[1][1]=tr[p].a[1]*tr[p].len;ok[2]=tr[p].f[2][2]=tr[p].a[2]*tr[p].len;ok[3]=tr[p].f[3][3]=tr[p].a[3]*tr[p].len;ok[4]=tr[p].f[4][4]=tr[p].a[1]*tr[p].len;for(int i=1;i<=4;i++)tr[p].f[i][i]+=tr[ls].f[i][i]+tr[rs].f[i][i];for(int len=2;len<=4;len++){for(int l=1;l+len-1<=4;l++){int r=l+len-1;for(int i=l;i<=r;i++){tr[p].f[l][r]=max(tr[p].f[l][r],tr[ls].f[l][i]+ok[i]+tr[rs].f[i][r]);}}}tr[p].siz=tr[ls].siz+tr[rs].siz+1;tr[p].al=tr[ls].al+tr[rs].al+tr[p].len;
}
int merge(int x,int y){if(!x||!y)return x|y;if(tr[x].w<tr[y].w){tr[x].rs=merge(tr[x].rs,y);pushup(x);return x;}tr[y].ls=merge(x,tr[y].ls);pushup(y);return y; }
void split(int id,int cnt,int&x,int&y){if(!id){x=y=0;return;}if(tr[tr[id].ls].al+tr[id].len<cnt){x=id;split(tr[id].rs,cnt-(tr[tr[id].ls].al+tr[id].len),tr[x].rs,y);pushup(x);}else{y=id;split(tr[y].ls,cnt,x,tr[y].ls);pushup(y);}
}
void split2(int id,int k,int&x,int &y){if(!id){x=y=0;return;}if(tr[tr[id].ls].siz+1<=k){x=id;split2(tr[id].rs,k-tr[tr[id].ls].siz-1,tr[x].rs,y);pushup(x);}else{y=id;split2(tr[y].ls,k,x,tr[y].ls);pushup(y);}
}
signed main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);srand(time(0));cin>>n;int lst=0;while(n--){int p,a,b,c,x;cin>>p>>a>>b>>c>>x;int T1,T2,T3;split(root,p,T1,T2);if(tr[T1].al!=p){split2(T2,1,T3,T2);int a=tr[T3].a[1],b=tr[T3].a[2],c=tr[T3].a[3],len=tr[T3].len;int x,xx;newnode(x,p-tr[T1].al,a,b,c);newnode(xx,len-(p-tr[T1].al),a,b,c);T1=merge(T1,x),T2=merge(xx,T2);}int t;newnode(t,x,a,b,c);root=merge(merge(T1,t),T2);int ans=tr[root].f[1][4];cout<<ans-lst<<'\n';lst=ans;}return 0;
}