#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
//存阀门,li表示第几段,si表示什么时刻打开
struct fa{
int li;
int si;
}fa[100005];
//存阀门打开后,水流的区间,ll是左区间,rr是右区间
struct qu{
int ll;
int rr;
}qujian[100005];
//n是有几个阀门,len是管道的长度
int n,len;
//排序,从小到大排序,先排左边界,再排右边界
bool cmp(qu a,qu b){
if(a.ll<b.ll) return true;
else if(a.ll==b.ll){
return a.rr<b.rr;
}
else return false;
}
//检查该ti时刻,水流能不能覆盖管道
bool check(int ti){
int cnt=0;//该ti时刻能打开的阀门数量
for(int i=0;i<n;i++){
if(fa[i].si>ti) continue;//当前时刻,该阀门还没到点,还没打开,所以跳过去
//存区间,代入题目的公式即可
qujian[cnt].ll=fa[i].li-(ti-fa[i].si);
qujian[cnt].rr=fa[i].li+(ti-fa[i].si);
cnt++;
}
sort(qujian,qujian+cnt,cmp);//区间排序,从小到大排序,先排左边界,再排右边界
if(qujian[0].ll>1) return false;//如果管道最左边都覆盖不了,那么直接return false
int last=-1;//last记录当前覆盖的管道最右侧,每遍历一个区间,更新一下
for(int i=0;i<cnt;i++){
if(qujian[i].ll>last+1) return false;//如果当前的区间最左端,无法覆盖掉目前水流的右侧
//即水流覆盖范围中间有空白,那么return false
last=max(qujian[i].rr,last);//更新一下last,取最大值
}
// cout<<"%";
if(last<len) return false;//如果管道最右边覆盖不了,return false
return true;
}
void solve(){
cin>>n>>len;
for(int i=0;i<n;i++){
cin>>fa[i].li>>fa[i].si;//存阀门
}
//二分答案,r取这个值是因为,如果管道最左侧的阀门在1e9时刻打开
//然后要覆盖到最右侧,但是管道长度1e9,那么总时长得2e9
int l=0,r=2000000005;
while(l<r){
int mid=l+r>>1;
if(check(mid)){
r=mid;
// cout<<"&";
}else{
// cout<<"*";
l=mid+1;
}
}
cout<<l;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
solve();
return 0;
}
2. 管道-二分
最新推荐文章于 2024-06-12 10:00:23 发布