{ }codelper
前缀和P0259

公交车最拥挤的路段

一条公交线路上依次有 1 号到 n 号车站。
公交车从 1 号站开到 n 号站,只跑一趟。
从 i 号站到 i+1 号站的路称为 i 号路段(1 ≤ i ≤ n − 1)。
有 m 名乘客,每名乘客给出两个整数 a、b。
这名乘客在 a 号站上车,在 b 号站下车(a < b)。
所以这名乘客在 a 号路段到 b − 1 号路段都在车上。
即使有别人在 b 号站上车,下车的人也不在 b 号路段。
统计每个路段车上的人数,求最多的人数。
在人数等于这个最多人数的路段中,还要求出最小的编号和最大的编号。
这样的路段只有一个时,两个编号相同。
在一行中输出最多的人数、最小的编号和最大的编号,用一个空格隔开。
第一行给出 n 和 m,接下来 m 行每行给出一名乘客的 a 和 b,用空格分开。

输入
2 ≤ n ≤ 9,999,1 ≤ m ≤ 10,000,1 ≤ a < b ≤ n(均为整数)
输出
一行:最多的人数、达到该人数的路段的最小编号和最大编号
样例 1 · stdin
5 4
1 3
2 5
3 4
4 5
stdout
2 2 4
样例 2 · stdin
4 3
1 2
2 3
3 4
stdout
1 1 3
main.py
输入(stdin)

运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 8 种语言题解

如果每名乘客都给 a 到 b − 1 号路段逐个加一,最坏是 10,000 人 × 9,998 路段,约 1 亿次,对 Python 和 Craykon 太慢。
改用差分列表。
每名乘客只写 diff[a] += 1 和 diff[b] -= 1,再从 1 号路段起往后累加(前缀和),累加值就是该路段的人数。
减的位置是陷阱。
乘客在 b 号站下车,所以要从 b 号路段开始减;在 diff[b + 1] 减的话,下车的人会多坐一个路段。
b 可以等于 n,所以列表需要 n + 1 格。
Java new int[n] 会抛出 ArrayIndexOutOfBoundsException,C# 抛出 IndexOutOfRangeException,C 则不报错地写到数组外面。
JS/TS new Array(n + 1) 只有空位,+= 1 会得到 NaN,要加上 .fill(0)。
Python [0] * (n + 1)、C++ std::vector<int>(n + 1, 0)、Craykon 新列表(n + 1, 0) 以及 Java/C# 的 int[] 一开始就是 0。
要一次找出第一个和最后一个路段,只在人数变大(>)时更新第一个路段,相等(==)时只更新最后一个路段。

Pythonmain.py · 20 行
import sys data = sys.stdin.buffer.read().split()n, m = int(data[0]), int(data[1])# 차이 목록: a번 구간부터 한 명 늘고, b번 구간부터 한 명 준다(b번 정류장에서 내리니까)diff = [0] * (n + 1)for k in range(m):    a, b = int(data[2 + 2 * k]), int(data[3 + 2 * k])    diff[a] += 1    diff[b] -= 1 load = 0best, first, last = -1, 0, 0for i in range(1, n):          # i번 구간: i번 → i+1번 정류장    load += diff[i]            # 앞에서부터 더하면 그 구간에 있는 사람 수    if load > best:        best, first, last = load, i, i    elif load == best:        last = iprint(best, first, last)
JavaScriptmain.js · 15 行
const nums = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const [n, m] = nums;// fill(0)이 없으면 빈 칸이라 += 1이 NaN이 된다const diff = new Array(n + 1).fill(0);for (let k = 0; k < m; k++) {  diff[nums[2 + 2 * k]] += 1;  diff[nums[3 + 2 * k]] -= 1;}let load = 0, best = -1, first = 0, last = 0;for (let i = 1; i < n; i++) {  load += diff[i];  if (load > best) [best, first, last] = [load, i, i];  else if (load === best) last = i;}console.log(`${best} ${first} ${last}`);
TypeScriptmain.ts · 15 行
import { readFileSync } from "node:fs";const nums: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const [n, m] = nums;const diff: number[] = new Array<number>(n + 1).fill(0);for (let k = 0; k < m; k++) {  diff[nums[2 + 2 * k]] += 1;  diff[nums[3 + 2 * k]] -= 1;}let load = 0, best = -1, first = 0, last = 0;for (let i = 1; i < n; i++) {  load += diff[i];  if (load > best) [best, first, last] = [load, i, i];  else if (load === best) last = i;}console.log(`${best} ${first} ${last}`);
JavaMain.java · 38 行
import java.io.DataInputStream;import java.io.IOException; public class Main {    static DataInputStream in = new DataInputStream(System.in);     static int readInt() throws IOException {        int c = in.read();        while (c < '0') c = in.read();        int r = 0;        while (c >= '0') {            r = r * 10 + (c - '0');            c = in.read();        }        return r;    }     public static void main(String[] args) throws IOException {        int n = readInt(), m = readInt();        int[] diff = new int[n + 1]; // b는 n까지 오니 n + 1칸        for (int k = 0; k < m; k++) {            int a = readInt(), b = readInt();            diff[a]++;            diff[b]--;        }        int load = 0, best = -1, first = 0, last = 0;        for (int i = 1; i < n; i++) {            load += diff[i];            if (load > best) {                best = load;                first = last = i;            } else if (load == best) {                last = i;            }        }        System.out.println(best + " " + first + " " + last);    }}
C#Main.cs · 25 行
using System;using System.IO; class Program{    static void Main()    {        string[] t = Console.In.ReadToEnd().Split((char[])null, StringSplitOptions.RemoveEmptyEntries);        int n = int.Parse(t[0]), m = int.Parse(t[1]);        var diff = new int[n + 1];        for (int k = 0; k < m; k++)        {            diff[int.Parse(t[2 + 2 * k])]++;            diff[int.Parse(t[3 + 2 * k])]--;        }        int load = 0, best = -1, first = 0, last = 0;        for (int i = 1; i < n; i++)        {            load += diff[i];            if (load > best) { best = load; first = last = i; }            else if (load == best) last = i;        }        Console.WriteLine($"{best} {first} {last}");    }}
C++main.cpp · 27 行
#include <iostream>#include <vector> int main() {    std::ios::sync_with_stdio(false);    std::cin.tie(nullptr);    int n, m;    std::cin >> n >> m;    std::vector<int> diff(n + 1, 0);    for (int k = 0; k < m; k++) {        int a, b;        std::cin >> a >> b;        diff[a]++;        diff[b]--;    }    int load = 0, best = -1, first = 0, last = 0;    for (int i = 1; i < n; i++) {        load += diff[i];        if (load > best) {            best = load;            first = last = i;        } else if (load == best) {            last = i;        }    }    std::cout << best << " " << first << " " << last << "\n";}
Cmain.c · 25 行
#include <stdio.h> static int diff[10000]; int main(void) {    int n, m, a, b;    scanf("%d %d", &n, &m);    for (int k = 0; k < m; k++) {        scanf("%d %d", &a, &b);        diff[a]++;   /* a번 구간부터 한 명 늘고 */        diff[b]--;   /* b번 정류장에서 내리니 b번 구간부터 준다 */    }    int load = 0, best = -1, first = 0, last = 0;    for (int i = 1; i < n; i++) {        load += diff[i];        if (load > best) {            best = load;            first = last = i;        } else if (load == best) {            last = i;        }    }    printf("%d %d %d\n", best, first, last);    return 0;}
Craykonmain.cray · 30 行
first = 控制台.读数字();n = first[0];m = first[1];// 차이 목록: a번 구간부터 한 명 늘고, b번 구간부터 한 명 준다diff = 新列表(n + 1, 0);循环 (k = 0; k < m; k++){    p = 控制台.读数字();    diff[p[0]] += 1;    diff[p[1]] -= 1;}load = 0;best = -1;from = 0;to = 0;循环 (i = 1; i < n; i++){    load += diff[i];    如果 (load > best)    {        best = load;        from = i;        to = i;    }    否则 如果 (load == best)    {        to = i;    }}控制台.输出(best + " " + from + " " + to);