Acwing5407管道

题目

有一根长度为 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≤len1,Li−1<Li

输入样例:

复制代码
3 10
1 1
6 5
10 2

输出样例:

复制代码
5

代码与思路

java 复制代码
import java.util.*;

public class Main {
    static class Pair implements Comparable<Pair> {
        int x, y;

        public Pair(int x, int y) {
            this.x = x;
            this.y = y;
        }

        @Override
        public int compareTo(Pair o) {
            return Integer.compare(this.x, o.x);
        }
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();  // 事件数量
        int m = in.nextInt();  // 区间右端点

        Pair[] w = new Pair[n];  // 事件数组
        for (int i = 0; i < n; i++) {
            int L = in.nextInt();  // 事件左端点
            int S = in.nextInt();  // 事件发生时间
            w[i] = new Pair(L, S);  // 构建事件 Pair 对象并加入数组
        }

        // 调用二分查找方法,找到满足条件的最小时间点
        int ans = binarySearch(w, m);
        System.out.println(ans);
    }

    // 检查是否存在一个时间点 mid,使得所有事件在该时间点前结束
    static boolean check(Pair[] w, int m, int mid) {
        List<Pair> q = new ArrayList<>();  // 存储事件在时间点 mid 时的区间范围
        for (int i = 0; i < w.length; i++) {
            int L = w[i].x;  // 事件 i 的左端点位置
            int S = w[i].y;  // 事件 i 的发生时间
            if (S <= mid) {  // 如果事件 i 在当前时间 mid 之前结束
                int t = mid - S;  // 计算事件 i 的持续时间
                int l = Math.max(1, L - t);  // 计算事件 i 在当前时间 mid 的左端点位置
                int r = Math.min(m, L + t);  // 计算事件 i 在当前时间 mid 的右端点位置
                q.add(new Pair(l, r));  // 将事件 i 的区间范围加入到列表中
            }
        }
        Collections.sort(q);  // 将事件按左端点位置进行排序

        int st = -1, ed = -1;  // 初始化起始和结束端点
        // 遍历事件列表,合并区间并更新起始和结束端点
        for (Pair p : q) {
            if (p.x <= ed + 1) {
                ed = Math.max(ed, p.y);  // 合并区间
            } else {
                st = p.x;
                ed = p.y;
            }
        }

        return st == 1 && ed == m;  // 检查是否覆盖了整个区间 [1, m]
    }

    // 二分查找满足条件的最小时间点
    static int binarySearch(Pair[] w, int m) {
        int l = 0, r = (int) 2e9;  // 初始化二分查找的左右边界
        while (l < r) {
            int mid = l + (r - l) / 2;  // 计算中间时间点
            if (check(w, m, mid)) {  // 如果当前时间点满足条件
                r = mid;  // 缩小右边界
            } else {
                l = mid + 1;  // 否则,增大左边界
            }
        }
        return r;  // 返回最小满足条件的时间点
    }
}
相关推荐
易协同低代码34 分钟前
通达OA核心类库TD类深度解析
后端
Gopher_HBo36 分钟前
Go语言学习笔记(十八)Gin处理Session
后端
谭光志1 小时前
工具塞满上下文窗口怎么办?深度拆解 AI Agent Tool Search 按需加载实现原理
前端·后端·ai编程
她说..2 小时前
Java 默认值设置方式
java·开发语言·后端·springboot
foggyprojects2 小时前
从0开始,一句话启动AI DataAgent
后端·数据分析·ai编程
郡杰2 小时前
一些基础和问题解决
后端
陈随易2 小时前
前端项目部署只要30秒
前端·后端·程序员
YIAN2 小时前
从零手写文件读取 MCP 服务:一文吃透 Model Context Protocol 全链路通信原理
前端·后端·mcp
Imchendiana2 小时前
《狂人日记NO.9》— 前后端一把梭,我的全栈实录
前端·后端
学渣超2 小时前
记一次分布式事务数据不一致的排查之旅:从超时到索引,层层剥茧
java·后端·架构