链接:https://ac.nowcoder.com/acm/contest/904/C
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
DongDong有一只超可爱的英短喜欢跳一跳,但此跳一跳非彼跳一跳
有n根柱子,每根柱子都有一个高度和柱子上面鱼干的数量,英短开始的时候可以选择站在任意一根柱子上,每次跳跃不限长度而且只能从左向右跳跃,但只能跳到高度与当前所站高度差绝对值小于等于m的柱子上,英短可贪心了,想吃最多的鱼干,请你设计一个程序能让英短吃到最多的鱼干(最终不一定要落在第n根柱子上)。
输入描述:
第一行给定两个整数,n,m 接下来n行,每行x,y表示这根柱子高度为x,上面有y根鱼干 数据范围:1<=n<=200000,1<=m<=500,对于每根柱子的x,y,1<=x<=1000000,1<=y<=1000000
输出描述:
输出英短最多可以吃到多少鱼干
示例1
输入
复制
4 4 1 0 2 100 100 5 6 10
输出
复制
110
地址:https://ac.nowcoder.com/acm/contest/904/C
思路:思维+线段树
由于x<=1e6较小,因此考虑能否从后推前,d[i]表示高度为i时能够得到的最大价值,每次维护d[xi-m]到d[xi+m]的最大值,而取第i个时,ax=max{d[xi-m],d[xi+m]}, ans=max(ans,ax+yi), 然后 更新 d[xi] = ax+yi; 而这可以用线段树来维护。
Code:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const int MAX_N=1e6+555;
struct tree{
int l,r;
LL x;
int mid(){
return (l+r)>>1;
}
};
int n,m;
int a[MAX_N],w[MAX_N];
tree Tree[MAX_N<<2];
void PushUp(int rt);
void Build(int l,int r,int rt);
void Update(int t,LL x,int rt);
LL Query(int l,int r,int rt);
int main()
{
scanf("%d%d",&n,&m);
Build(1,MAX_N-5,1);
for(int i=1;i<=n;++i)
scanf("%d%d",&a[i],&w[i]);
LL ans=0,ax;
int l,r;
for(int i=1;i<=n;++i)
{
l=max(0,a[i]-m); r=a[i]+m;
ax=Query(l,r,1);
Update(a[i],ax+w[i],1);
ans=max(ans,ax+w[i]);
}
printf("%lld\n",ans);
return 0;
}
void PushUp(int rt)
{
Tree[rt].x=max(Tree[rt<<1].x,Tree[rt<<1|1].x);
}
void Build(int l,int r,int rt)
{
Tree[rt].l=l; Tree[rt].r=r;
Tree[rt].x=0;
if(l==r){
return;
}
int h=(l+r)>>1;
Build(l,h,rt<<1);
Build(h+1,r,rt<<1|1);
PushUp(rt);
}
void Update(int t,LL x,int rt)
{
if(Tree[rt].l==Tree[rt].r){
Tree[rt].x=x;
return;
}
int h=Tree[rt].mid();
if(t<=h){
Update(t,x,rt<<1);
}else Update(t,x,rt<<1|1);
PushUp(rt);
}
LL Query(int l,int r,int rt)
{
if(l<=Tree[rt].l&&r>=Tree[rt].r){
return Tree[rt].x;
}
int h=Tree[rt].mid();
LL res=0;
if(h>=l) res=max(res,Query(l,r,rt<<1));
if(h+1<=r) res=max(res,Query(l,r,rt<<1|1));
return res;
}