有 n 棵植株排成一排,第 i 棵植株的高度、价值和拔除的花费分别为 hi 、 pi 和 ci 。
能够获得第 i 棵植株的价值,当且仅当这棵植株左边所有高度大于它的植株都被拔除,或者右边所有高度大于它的植株都被拔除。
最大化收益(价值和与花费和的差)。
3≤n≤105,1≤hi,pi,ci≤109
我们观察获得价值的条件,按照 x 轴为编号, y 轴为高度,显然最终贡献价值的植株构成的图像就是一个开口朝下的单峰函数(可以特殊化成一条单调不上升/不下降的曲线)。
我们枚举函数最高点,然后求两边答案最大值之和即可。两边答案求法类似,我们只讨论从左到右。
设 fi 表示选择第 i 棵植株能造成的最大收益,先列出最暴力的 dp 方程:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cctype>
using namespace std;
typedef long long LL;
int read()
{
int x=0,f=1;
char ch=getchar();
while (!isdigit(ch))
{
if (ch=='-')
f=-1;
ch=getchar();
}
while (isdigit(ch))
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
const int N=100500;
struct D
{
int v,id;
}s[N];
bool operator<(D a,D b)
{
return a.v<b.v;
}
struct segment_tree
{
LL tag[N<<2][2],mx[N<<2];//0:add;1:max
bool tg[N<<2];
void init()
{
memset(tag,0,sizeof tag);
memset(tg,0,sizeof tg);
memset(mx,0,sizeof mx);
}
void merge(int x,LL y,bool tp)
{
if (!tp)
tag[x][0]+=y;
else
{
if (tg[x])
tag[x][1]=max(tag[x][1],y-tag[x][0]);
else
tag[x][1]=y-tag[x][0];
tg[x]=true;
}
}
void mark(int x,LL y,bool tp)
{
merge(x,y,tp);
if (!tp)
mx[x]+=y;
else
mx[x]=max(mx[x],y);
}
void clear(int x,int l,int r)
{
if (l==r)
return;
if (tag[x][1])
{
mark(x<<1,tag[x][1],1),mark(x<<1|1,tag[x][1],1);
tag[x][1]=0;
tg[x]=false;
}
if (tag[x][0])
{
mark(x<<1,tag[x][0],0),mark(x<<1|1,tag[x][0],0);
tag[x][0]=0;
}
}
void update(int x)
{
mx[x]=max(mx[x<<1],mx[x<<1|1]);
}
LL query(int x,int y,int l,int r)
{
clear(x,l,r);
if (l==r)
return mx[x];
int mid=l+r>>1;
if (y<=mid)
return query(x<<1,y,l,mid);
else
return query(x<<1|1,y,mid+1,r);
}
void change(int x,int st,int en,int l,int r,bool tp,LL edit)
{
clear(x,l,r);
if (st==l&&en==r)
{
mark(x,edit,tp);
return;
}
int mid=l+r>>1;
if (en<=mid)
change(x<<1,st,en,l,mid,tp,edit);
else
if (mid+1<=st)
change(x<<1|1,st,en,mid+1,r,tp,edit);
else
change(x<<1,st,mid,l,mid,tp,edit),change(x<<1|1,mid+1,en,mid+1,r,tp,edit);
update(x);
}
}t;
int h[N],p[N],c[N],lab[N];
LL f[2][N];
int n,ind;
LL ans;
int main()
{
freopen("herbary.in","r",stdin);
freopen("herbary.out","w",stdout);
n=read();
for (int i=1;i<=n;i++)
h[i]=read(),p[i]=read(),c[i]=read();
for (int i=1;i<=n;i++)
s[i].v=h[i],s[i].id=i;
sort(s+1,s+1+n);
ind=0;
for (int i=1;i<=n;i++)
lab[s[i].id]=(s[i].v==s[i-1].v)?ind:++ind;
t.init();
for (int i=1;i<=n;i++)
{
LL get=t.query(1,lab[i],1,ind);
f[0][i]=get+p[i];
if (lab[i]>1)
t.change(1,1,lab[i]-1,1,ind,0,-c[i]);
t.change(1,lab[i],ind,1,ind,1,f[0][i]);
}
for (int i=2;i<=n;i++)
f[0][i]=max(f[0][i],f[0][i-1]);
t.init();
for (int i=n;i>=1;i--)
{
LL get=t.query(1,lab[i],1,ind);
f[1][i]=get+p[i];
if (lab[i]>1)
t.change(1,1,lab[i]-1,1,ind,0,-c[i]);
t.change(1,lab[i],ind,1,ind,1,f[1][i]);
}
for (int i=n-1;i>=1;i--)
f[1][i]=max(f[1][i],f[1][i+1]);
for (int i=1;i<n;i++)
ans=max(f[0][i]+f[1][i+1],ans);
ans=max(max(f[0][n],f[1][1]),ans);
printf("%lld\n",ans);
fclose(stdin);
fclose(stdout);
return 0;
}