给出一间会议室一天的 n 个预约和 q 个问题。 时刻是非负整数。 第一行给出 n 和 q。 接下来 n 行每行以 "s e" 的形式给出一个预约。 这个预约从时刻 s 开始使用会议室,直到 e 之前。 所以时刻 s 在使用中,时刻 e 不再被这个预约使用。 预约按开始时刻从早到晚给出,互不重叠。 但前一个预约结束的时刻,下一个预约可以立刻开始。 这样的预约称为相接。 最后一行给出 q 个要询问的时刻 t,用空格分开。 对每个问题输出一行答案。 如果时刻 t 有预约在使用会议室,输出 "busy X"。 X 是这个预约以及之后相接的预约全部结束、会议室第一次空出来的时刻。 如果时刻 t 没有预约在使用,输出 "free Y"。 Y 是在 t 之后开始的预约中最早那个的开始时刻。 如果 t 之后没有开始的预约,输出 "free none"。 预约和问题都很多,不要每个问题都从头扫描预约,要用对半查找。
输入
1 ≤ n ≤ 10,000,1 ≤ q ≤ 10,000,0 ≤ s < e ≤ 1,000,000,000,前一个预约的 e ≤ 下一个预约的 s,0 ≤ t ≤ 1,000,000,000
import sysfrom bisect import bisect_rightdata = sys.stdin.read().split()n, q = int(data[0]), int(data[1])S = [int(x) for x in data[2:2 + 2 * n:2]]E = [int(x) for x in data[3:3 + 2 * n:2]]queries = data[2 + 2 * n:]# block_end[i]: i번 예약부터 맞닿은 예약을 따라가다 처음 비는 시각(뒤에서부터 채운다)block_end = E[:]for i in range(n - 2, -1, -1): if E[i] == S[i + 1]: block_end[i] = block_end[i + 1]out = []for t in map(int, queries): i = bisect_right(S, t) - 1 # 시작 시각이 t 이하인 마지막 예약(없으면 -1) if i >= 0 and t < E[i]: # i가 -1이면 E[-1]이 마지막 예약이 되니 먼저 확인한다 out.append(f"busy {block_end[i]}") elif i + 1 < n: out.append(f"free {S[i + 1]}") else: out.append("free none")print("\n".join(out))
JavaScriptmain.js · 31 行
const data = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const [n, q] = data;const S = [], E = [];for (let i = 0; i < n; i++) { S.push(data[2 + 2 * i]); E.push(data[3 + 2 * i]);}// blockEnd[i]: i번 예약부터 맞닿은 예약을 따라가다 처음 비는 시각(뒤에서부터 채운다)const blockEnd = E.slice();for (let i = n - 2; i >= 0; i--) if (E[i] === S[i + 1]) blockEnd[i] = blockEnd[i + 1];// 시작 시각이 t 이하인 마지막 예약의 번호(없으면 -1)function lastStartAtMost(t) { let lo = 0, hi = n; // 답은 [lo, hi) 바로 앞: S[0..lo)는 t 이하, S[hi..n)은 t 초과 while (lo < hi) { const mid = (lo + hi) >> 1; if (S[mid] <= t) lo = mid + 1; else hi = mid; } return lo - 1;}const out = [];for (let j = 0; j < q; j++) { const t = data[2 + 2 * n + j]; const i = lastStartAtMost(t); if (i >= 0 && t < E[i]) out.push(`busy ${blockEnd[i]}`); else if (i + 1 < n) out.push(`free ${S[i + 1]}`); else out.push("free none");}console.log(out.join("\n"));
TypeScriptmain.ts · 32 行
import { readFileSync } from "node:fs";const data: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const [n, q] = data;const S: number[] = [], E: number[] = [];for (let i = 0; i < n; i++) { S.push(data[2 + 2 * i]); E.push(data[3 + 2 * i]);}// blockEnd[i]: i번 예약부터 맞닿은 예약을 따라가다 처음 비는 시각(뒤에서부터 채운다)const blockEnd: number[] = E.slice();for (let i = n - 2; i >= 0; i--) if (E[i] === S[i + 1]) blockEnd[i] = blockEnd[i + 1];// 시작 시각이 t 이하인 마지막 예약의 번호(없으면 -1)function lastStartAtMost(t: number): number { let lo = 0, hi = n; // S[0..lo)는 t 이하, S[hi..n)은 t 초과 while (lo < hi) { const mid: number = (lo + hi) >> 1; if (S[mid] <= t) lo = mid + 1; else hi = mid; } return lo - 1;}const out: string[] = [];for (let j = 0; j < q; j++) { const t: number = data[2 + 2 * n + j]; const i: number = lastStartAtMost(t); if (i >= 0 && t < E[i]) out.push(`busy ${blockEnd[i]}`); else if (i + 1 < n) out.push(`free ${S[i + 1]}`); else out.push("free none");}console.log(out.join("\n"));
JavaMain.java · 46 行
import java.io.BufferedReader;import java.io.InputStreamReader;import java.util.StringTokenizer;public class Main { static int n; static int[] S, E; // 시작 시각이 t 이하인 마지막 예약의 번호(없으면 -1) static int lastStartAtMost(int t) { int lo = 0, hi = n; // S[0..lo)는 t 이하, S[hi..n)은 t 초과 while (lo < hi) { int mid = (lo + hi) >>> 1; if (S[mid] <= t) lo = mid + 1; else hi = mid; } return lo - 1; } public static void main(String[] args) throws Exception { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(in.readLine()); n = Integer.parseInt(st.nextToken()); int q = Integer.parseInt(st.nextToken()); S = new int[n]; E = new int[n]; for (int i = 0; i < n; i++) { st = new StringTokenizer(in.readLine()); S[i] = Integer.parseInt(st.nextToken()); E[i] = Integer.parseInt(st.nextToken()); } // blockEnd[i]: i번 예약부터 맞닿은 예약을 따라가다 처음 비는 시각(뒤에서부터 채운다) int[] blockEnd = E.clone(); for (int i = n - 2; i >= 0; i--) if (E[i] == S[i + 1]) blockEnd[i] = blockEnd[i + 1]; st = new StringTokenizer(in.readLine()); StringBuilder out = new StringBuilder(); for (int j = 0; j < q; j++) { int t = Integer.parseInt(st.nextToken()); int i = lastStartAtMost(t); if (i >= 0 && t < E[i]) out.append("busy ").append(blockEnd[i]).append('\n'); else if (i + 1 < n) out.append("free ").append(S[i + 1]).append('\n'); else out.append("free none\n"); } System.out.print(out); }}
C#Main.cs · 35 行
using System;using System.Text;class Program{ static void Main() { string[] first = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries); int n = int.Parse(first[0]), q = int.Parse(first[1]); int[] S = new int[n], E = new int[n]; for (int i = 0; i < n; i++) { string[] p = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries); S[i] = int.Parse(p[0]); E[i] = int.Parse(p[1]); } // blockEnd[i]: i번 예약부터 맞닿은 예약을 따라가다 처음 비는 시각(뒤에서부터 채운다) int[] blockEnd = (int[])E.Clone(); for (int i = n - 2; i >= 0; i--) if (E[i] == S[i + 1]) blockEnd[i] = blockEnd[i + 1]; string[] qs = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries); var sb = new StringBuilder(); for (int j = 0; j < q; j++) { int t = int.Parse(qs[j]); // Array.BinarySearch는 같은 값이 없으면 ~(t보다 큰 첫 자리)를 돌려준다. // 시작 시각은 모두 다르니, 찾으면 그 자리, 못 찾으면 그 앞 자리가 "t 이하인 마지막"이다 int pos = Array.BinarySearch(S, t); int i = pos >= 0 ? pos : ~pos - 1; if (i >= 0 && t < E[i]) sb.Append("busy ").Append(blockEnd[i]).Append('\n'); else if (i + 1 < n) sb.Append("free ").Append(S[i + 1]).Append('\n'); else sb.Append("free none\n"); } Console.Write(sb); }}
C++main.cpp · 27 行
#include <algorithm>#include <iostream>#include <string>#include <vector>int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int n, q; std::cin >> n >> q; std::vector<int> S(n), E(n); for (int i = 0; i < n; i++) std::cin >> S[i] >> E[i]; // blockEnd[i]: i번 예약부터 맞닿은 예약을 따라가다 처음 비는 시각(뒤에서부터 채운다) std::vector<int> blockEnd = E; for (int i = n - 2; i >= 0; i--) if (E[i] == S[i + 1]) blockEnd[i] = blockEnd[i + 1]; std::string out; for (int j = 0; j < q; j++) { int t; std::cin >> t; // upper_bound는 t보다 큰 첫 자리. 그 바로 앞이 시작 시각이 t 이하인 마지막 예약이다 int i = int(std::upper_bound(S.begin(), S.end(), t) - S.begin()) - 1; if (i >= 0 && t < E[i]) out += "busy " + std::to_string(blockEnd[i]) + "\n"; else if (i + 1 < n) out += "free " + std::to_string(S[i + 1]) + "\n"; else out += "free none\n"; } std::cout << out;}
Cmain.c · 33 行
#include <stdio.h>static int S[10000], E[10000], blockEnd[10000];static int n;/* 시작 시각이 t 이하인 마지막 예약의 번호(없으면 -1) */int last_start_at_most(int t) { int lo = 0, hi = n; /* S[0..lo)는 t 이하, S[hi..n)은 t 초과 */ while (lo < hi) { int mid = lo + (hi - lo) / 2; if (S[mid] <= t) lo = mid + 1; else hi = mid; } return lo - 1;}int main(void) { int q, t; scanf("%d %d", &n, &q); for (int i = 0; i < n; i++) scanf("%d %d", &S[i], &E[i]); /* blockEnd[i]: i번 예약부터 맞닿은 예약을 따라가다 처음 비는 시각(뒤에서부터 채운다) */ for (int i = n - 1; i >= 0; i--) { blockEnd[i] = (i + 1 < n && E[i] == S[i + 1]) ? blockEnd[i + 1] : E[i]; } for (int j = 0; j < q; j++) { scanf("%d", &t); int i = last_start_at_most(t); if (i >= 0 && t < E[i]) printf("busy %d\n", blockEnd[i]); else if (i + 1 < n) printf("free %d\n", S[i + 1]); else puts("free none"); } return 0;}
Craykonmain.cray · 58 行
첫줄 = 控制台.读数字();n = 첫줄[0];q = 첫줄[1];S = [];E = [];循环 (i = 0; i < n; i++){ p = 控制台.读数字(); S.添加(p[0]); E.添加(p[1]);}// blockEnd[i]: i번 예약부터 맞닿은 예약을 따라가다 처음 비는 시각(뒤에서부터 채운다)blockEnd = E.子列表(0, n);循环 (i = n - 2; i >= 0; i--){ 如果 (E[i] == S[i + 1]) { blockEnd[i] = blockEnd[i + 1]; }}// 시작 시각이 t 이하인 마지막 예약의 번호(없으면 -1)마지막시작(t){ lo = 0; hi = n; // S[0..lo)는 t 이하, S[hi..n)은 t 초과 当 (lo < hi) { mid = 数学.商(lo + hi, 2); // /는 소수까지 나누니 몫을 쓴다 如果 (S[mid] <= t) { lo = mid + 1; } 否则 { hi = mid; } } 返回 lo - 1;}qs = 控制台.读数字();遍历 (t 在 qs){ i = 마지막시작(t); 如果 (i >= 0 && t < E[i]) { 控制台.输出("busy " + blockEnd[i]); } 否则 如果 (i + 1 < n) { 控制台.输出("free " + S[i + 1]); } 否则 { 控制台.输出("free none"); }}