有一根长度为 len 的横向的管道,该管道按照单位长度分为 len段,每一段的中央有一个可开关的阀门和一个检测水流的传感器。
一开始管道是空的,位于 Li的阀门会在 Si时刻打开,并不断让水流入管道。
对于位于 Li的阀门,它流入的水在 Ti(Ti≥Si)时刻会使得从第 Li−(Ti−Si) 段到第 Li+(Ti−Si)段的传感器检测到水流。
求管道中每一段中间的传感器都检测到有水流的最早时间。
输入格式
输入的第一行包含两个整数 n,len,用一个空格分隔,分别表示会打开的阀门数和管道长度。
接下来 n行每行包含两个整数 Li,Si,用一个空格分隔,表示位于第 Li 段管道中央的阀门会在 Si
时刻打开。
输出格式
输出一行包含一个整数表示答案。
数据范围
对于 30%
的评测用例,n≤200,Si,len≤3000;
对于 70% 的评测用例,n≤5000,Si,len≤105;
对于所有评测用例,1≤n≤105,1≤Si,len≤109,1≤Li≤len,Li−1<Li。
输入样例:
3 10
1 1
6 5
10 2
输出样例:
5
#include <iostream>
#include <cstring>
#include <algorithm>
#define x first
#define y second
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 100010;
int n, m;
PII w[N], q[N];//w来表示初始的l和s q表示二分后每一个对应的左端点
bool check(int mid)
{
int cnt = 0;//记录打开的水管
for (int i = 0; i < n; i ++ )
{
int L = w[i].x, S = w[i].y;
if (S <= mid)//如果水管打开的时刻小于二分时刻
{
int t = mid - S;//t就是水走了多少位置
int l = max(1, L - t), r = min((LL)m, (LL)L + t);//水流过的左右位置,要在范围内更新
q[cnt ++ ] = {l, r};
}
}
//排序后,区间合并
sort(q, q + cnt);
int st = -1, ed = -1; // 初始化起始点和终点为-1
for (int i = 0; i < cnt; i ++ ) // 遍历区间数组q
if (q[i].x <= ed + 1) ed = max(ed, q[i].y); // 如果当前区间与上一个区间有重叠,则更新终点
else st = q[i].x, ed = q[i].y; // 否则,更新起始点和终点
return st == 1 && ed == m; // 返回是否满足条件,即起始点为1且终点为m
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i ++ ) scanf("%d%d", &w[i].x, &w[i].y);
//二分(二分的是时刻)
int l = 0, r = 2e9;//2e9是因为len≤10^9若是有10^9长的管道,且只有最后一地方有口,且在si=10^9时刻打开就是最大的了
while (l < r)
{
int mid = (LL)l + r >> 1;//强制转换,可能爆int
if (check(mid)) r = mid;
else l = mid + 1;
}
printf("%d\n", r);
return 0;
}