题目描述
有一根长度为 len 的横向的管道,该管道按照单位长度分为 len 段,每一段的中央有一个可开关的阀门和一个检测水流的传感器。
一开始管道是空的,位于 Li 的阀门会在 Si 时刻打开,并不断让水流入管道。
对于位于 Li 的阀门,它流入的水在 Ti (Ti ≥ Si) 时刻会使得从第 Li−(Ti−Si) 段到第 Li + (Ti − Si) 段的传感器检测到水流。 求管道中每一段中间的传感器都检测到有水流的最早时间。
思路
(一开始没有弄懂题目意思,以为是覆盖所有给定的阀门就行,结果浪费不少时间,,一定先要读懂题啊啊啊)
题目意思大概是:给定一个1~len的区间,区间里面有n个水闸分别会在ti时刻放水,求水将整个区间全部覆盖所需的最少时间。
明显这个时间是线性的,即时间越长,覆盖的范围越大。所以我们可以二分这个时间。
在时间t下,枚举出每个水闸覆盖的区间,得到若干个区间。然后对这些区间先进行初步排序,然后进行区间合并。如果合并后的区间覆盖了完整的1~len的区间,则check返回true。
注意点:
1、记得先要对区间进行排序,再进行区间合并
2、二分的边界是1~2e9+1,因为最差的情况是1e9时开始放水,然后再要跑1e9个格子,所以总共需要2e9+1的时间。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
struct node{
int pos;
int t;
};
struct edg{
int l;
int r;
};
bool cmp(node a,node b){
return a.pos<b.pos;
}
bool cmp1(edg a,edg b){
if(a.l!=b.l)
return a.l<b.l;
return a.r<b.r;
}
vector<node>q;
int n,m;
bool check(int k){
vector<edg>e;
for(int i=0;i<n;i++){
if(k<q[i].t)continue;
int sub=k-q[i].t;
int l=q[i].pos-sub;
int r=q[i].pos+sub;
e.push_back({l,r});
}
if(e.size()==0)return 0;
sort(e.begin(),e.end(),cmp1);
if(e[0].l>1)return 0;
int i=0;
int r=e[i].r;
i++;
while(i<e.size()&&r>=e[i].l-1){
r=max(r,e[i].r);
i++;
}
return r>=m;
}
signed main(){
cin>>n>>m;
for(int i=0;i<n;i++){
int a,b;cin>>a>>b;
q.push_back({a,b});
}
int l=1,r=2e9+10;
while(l<r){
int mid=r+l>>1;
if(check(mid))r=mid;
else l=mid+1;
}
cout<<l;
}