题目传送门:https://www.luogu.org/problemnew/show/P1901
题意:
有n个发射站,它们有对应的高度和能量。每个发射站发出的能量都会被两边离它最近且比它高的能量站接收到,从而获得当前能量站的能量(当前能量站不扣除能量)。求获得最大能量的能量站的能量是多少。
思路:
一眼想到了单调队列(单调栈会更容易,但实用性没有那么好),转念一想,单调队列处理队列里的元素确实有些麻烦。
于是,一种类似于dp的方法就浮现在我脑子里。
设f1[i]表示i能量站左边的离它最近且比它高的能量站的编号(如果没有,则为-1),
f2[i]表示i能量站左边的离它最近且比它高的能量站的编号(如果没有,则为-1)。
很明显,我们每一次走到一个点i,只需要跳到对应f1[i],f2[i]即可,因为在f1[i]+1~i-1,i+1~f2[i]-1区间没有比i能量站高的能量站,而我们每一次求x号能量站,只需要从i-1和i+1开始做即可。
注意边界之类的判断,调了我近一个小时。
代码:
#include<cstdio>
#include<algorithm>
#define LL long long
#define R register
using namespace std;
int n;
LL ans=0;
int a[1000010],v[1000010],f1[1000010],f2[1000010];
LL tot[1000010];
inline int readint()
{
int f=1,x=0;
char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())
if(ch=='-') f=-1;
for(;ch>='0'&&ch<='9';x=(x<<3)+(x<<1)+(ch^48),ch=getchar());
return x*f;
}
int main()
{
n=readint();
for(R int i=1;i<=n;i++)
a[i]=readint(),v[i]=readint();
f1[0]=-1;
f2[n+1]=-1;
for(R int i=1;i<=n;i++)
{
int l=i-1;
while(l!=-1&&a[l]<=a[i])
l=f1[l];
if(l!=-1) tot[l]+=v[i],f1[i]=l; else f1[i]=-1;
}
for(int R i=n;i>=1;i--)
{
int r=i+1;
while(r!=-1&&a[r]<=a[i])
r=f2[r];
if(r!=-1) tot[r]+=v[i],f2[i]=r; else f2[i]=-1;
}
for(R int i=1;i<=n;i++)
ans=max(ans,tot[i]);
printf("%lld",ans);
}