Description
有
n
个景点,景点之间通过缆车链接,上缆车需要票,有
Input
第一行两个整数
(2≤n≤50000,n−1≤m≤109,1≤pi≤105,1≤di≤105)
Output
输出最少花费
Sample Input
4 4
1 2 3
1 4
Sample Output
2
Solution
关键在于求出最小范围,之后在所有范围不低于该最小范围的票里选最便宜的即可,二分范围,对于一个范围
r
,令
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
#define maxn 50005
const ll INF=1e18;
int n,m,d[maxn],p[maxn];
ll dp[maxn],Min[maxn<<2],Lazy[maxn<<2];
#define ls (t<<1)
#define rs ((t<<1)|1)
void push_up(int t)
{
Min[t]=min(Min[ls],Min[rs]);
}
void build(int l,int r,int t)
{
Lazy[t]=0;
if(l==r)
{
Min[t]=d[l];
return ;
}
int mid=(l+r)/2;
build(l,mid,ls),build(mid+1,r,rs);
push_up(t);
}
void push_down(int t)
{
if(Lazy[t])
{
Lazy[ls]+=Lazy[t],Lazy[rs]+=Lazy[t];
Min[ls]+=Lazy[t],Min[rs]+=Lazy[t];
Lazy[t]=0;
}
}
void update(int L,int R,int l,int r,int t,ll v)
{
if(L<=l&&r<=R)
{
Min[t]+=v,Lazy[t]+=v;
return ;
}
push_down(t);
int mid=(l+r)/2;
if(L<=mid)update(L,R,l,mid,ls,v);
if(R>mid)update(L,R,mid+1,r,rs,v);
push_up(t);
}
ll query(int L,int R,int l,int r,int t)
{
if(L<=l&&r<=R)return Min[t];
push_down(t);
int mid=(l+r)/2;
ll ans=INF;
if(L<=mid)ans=min(ans,query(L,R,l,mid,ls));
if(R>mid)ans=min(ans,query(L,R,mid+1,r,rs));
return ans;
}
bool check(int r)
{
build(1,n,1);
dp[1]=0;
for(int i=2;i<=n;i++)
{
update(1,i-1,1,n,1,1);
dp[i]=query(max(1,i-r),i-1,1,n,1);
update(i,i,1,n,1,dp[i]);
}
if(dp[n]<=m)return 1;
return 0;
}
int main()
{
freopen("journey.in","r",stdin);
freopen("journey.out","w",stdout);
while(~scanf("%d%d",&n,&m))
{
for(int i=1;i<n;i++)scanf("%d",&p[i]);
for(int i=2;i<=n-1;i++)scanf("%d",&d[i]);
d[1]=d[n]=0;
int l=1,r=n-1,mid,ansr=n-1;
while(l<=r)
{
mid=(l+r)/2;
if(check(mid))ansr=mid,r=mid-1;
else l=mid+1;
}
int ans=p[ansr];
for(int i=ansr+1;i<n;i++)ans=min(ans,p[i]);
printf("%d\n",ans);
}
return 0;
}