https://codeforces.com/problemset/problem/1041/D
思路:
可以发现,选择的起点在当前某个线段区间的左端点一定不会更差。
于是On枚举起点位置,快速找到其终点在的区间。下降的过程满足单调性,于是二分最终所在的区间。中间的check用前缀和处理区间的差值的累加就可以O1check了。
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=2e5+1000;
typedef long long LL;
inline LL read(){LL x=0,f=1;char ch=getchar(); while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;}
struct P{
LL l,r;
}a[maxn];
LL sum[maxn];
bool check(LL p,LL q,LL n,LL h){
LL downdis=sum[q]-sum[p];
/// cout<<"p="<<p<<" "<<"q="<<q<<" "<<"downdis="<<downdis<<"\n";
if(h-downdis>0) return true;
else return false;
}
int main(void)
{
cin.tie(0);std::ios::sync_with_stdio(false);
LL n,h;cin>>n>>h;
for(LL i=1;i<=n;i++){
cin>>a[i].l>>a[i].r;
}
sum[1]=0;
for(LL i=2;i<=n;i++){
sum[i]=sum[i-1]+(a[i].l-a[i-1].r);
}
LL ans=0;
for(LL i=1;i<=n;i++){///枚举起点,处于某个线段区间的左端点
LL l=i;LL r=n;
while(l<r){
LL mid=(l+r+1)>>1;
if(check(i,mid,n,h)) l=mid;
else r=mid-1;
}
/// cout<<"i="<<i<<" "<<"l="<<l<<"\n";
LL res1=a[l].r-a[i].l;
LL temp=h;
temp-=(sum[l]-sum[i]);
res1+=temp;
ans=max(ans,res1);
}
cout<<ans<<"\n";
return 0;
}