先考虑按时间顺序转移,可以写出状态
O(n)
,转移
O(n)
的方程。线段树优化可以做到
O(logn)
转移。
接下来考虑相同时间之间的转移。按照位置的顺序正反扫一遍就可以了。
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=4000010,oo=0x3f3f3f3f;
int rd()
{
int x=0;
char c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9')
{
x=x*10+c-'0';
c=getchar();
}
return x;
}
struct str
{
int t,p,w;
bool operator < (const str &s) const
{
if (t!=s.t) return t<s.t;
return p<s.p;
}
}a[maxn];
int dp[maxn],f[maxn],g[maxn],mx[2][maxn],n,m,U,D,S;
void build(int u,int L,int R)
{
if (L==R)
{
if (L==S) mx[0][u]=D*S,mx[1][u]=-U*S;
else mx[0][u]=mx[1][u]=-oo;
return;
}
int mid=(L+R)/2;
build(u*2,L,mid);
build(u*2+1,mid+1,R);
mx[0][u]=max(mx[0][u*2],mx[0][u*2+1]);
mx[1][u]=max(mx[1][u*2],mx[1][u*2+1]);
}
int qry(int f,int u,int L,int R,int l,int r)
{
if (l<=L&&R<=r) return mx[f][u];
int mid=(L+R)/2,ret=-oo;
if (l<=mid) ret=qry(f,u*2,L,mid,l,r);
if (r>mid) ret=max(ret,qry(f,u*2+1,mid+1,R,l,r));
return ret;
}
void modi(int u,int L,int R,int k)
{
if (L==R)
{
mx[0][u]=dp[k]+D*a[k].p;
mx[1][u]=dp[k]-U*a[k].p;
return;
}
int mid=(L+R)/2;
if (a[k].p<=mid) modi(u*2,L,mid,k);
else modi(u*2+1,mid+1,R,k);
mx[0][u]=max(mx[0][u*2],mx[0][u*2+1]);
mx[1][u]=max(mx[1][u*2],mx[1][u*2+1]);
}
int main()
{
//freopen("e.in","r",stdin);
n=rd();
U=rd();
D=rd();
S=rd();
m=S;
for (int i=1;i<=n;i++)
{
a[i].t=rd();
a[i].p=rd();
a[i].w=rd();
m=max(m,a[i].p);
}
sort(a+1,a+n+1);
n++;
a[n]=(str){a[n-1].t+1,S,0};
build(1,1,m);
for (int i=1,j;i<=n;i=j+1)
{
for (j=i;j<n&&a[j+1].t==a[i].t;j++);
for (int k=i;k<=j;k++)
dp[k]=max(qry(0,1,1,m,1,a[k].p)-D*a[k].p,qry(1,1,1,m,a[k].p,m)+U*a[k].p)+a[k].w;
f[i]=dp[i];
for (int k=i+1;k<=j;k++)
f[k]=max(dp[k],f[k-1]-D*(a[k].p-a[k-1].p)+a[k].w);
g[j]=dp[j];
for (int k=j-1;k>=i;k--)
g[k]=max(dp[k],g[k+1]-U*(a[k+1].p-a[k].p)+a[k].w);
for (int k=i;k<=j;k++)
{
dp[k]=max(dp[k],max(f[k],g[k]));
modi(1,1,m,k);
}
}
printf("%d\n",dp[n]);
}