题解:洛谷 AT_abc463_c Tallest at the Moment

【题目来源】

洛谷:AT_abc463_c [ABC463C] Tallest at the Moment - 洛谷

【题目描述】

Currently, there are \(N\) Takahashi in a conference room. The \(i\)-th \((1\le i\le N)\) Takahashi has a height of \(H _ i\) and will leave the room \(L _ i\) minutes from now. Once a Takahashi leaves the room, he never returns.

You are given \(Q\) queries, so answer them in order. For the \(i\)-th \((1\le i\le Q)\) query, you are given an integer \(T _ i\), so find the maximum height among the Takahashi who are in the room \(T _ i+\dfrac12\) minutes from now. Under the constraints of this problem, it is guaranteed that at least one Takahashi will be in the room \(T _ i+\dfrac12\) minutes from now.

当前会议室里有 \(N\) 个高橋。第 \(i\)\((1\le i\le N)\) 高橋的身高为 \(H_i\),他将在 \(L_i\) 分钟后离开房间。一旦高橋离开房间,他就不会再回来。

给定 \(Q\) 个查询,请按顺序回答。对于第 \(i\)\((1\le i\le Q)\) 查询,给定一个整数 \(T_i\),请找出 \(T_i+\dfrac12\) 分钟后仍在房间里的高橋中的最大身高。在本题的约束条件下,保证 \(T_i+\dfrac12\) 分钟后房间里至少还有一个高橋。

【输入】

The input is given from Standard Input in the following format:

\(N\)
\(H _ 1\) \(L _ 1\)
\(H _ 2\) \(L _ 2\)
\(\vdots\)
\(H _ N\) \(L _ N\)
\(Q\)
\(T _ 1\) \(T _ 2\) \(\ldots\) \(T _ Q\)

【输出】

Output \(Q\) lines. The \(i\)-th line \((1\le i\le Q)\) should contain the answer to the \(i\)-th query.

【输入样例】

4
31 4
26 5
3 5
15 9
4
3 4 5 6

【输出样例】

31
26
15
15

【核心思想】

  1. 问题分析:给定 \(N\) 个人,每人有身高 \(H_i\) 和离开时间 \(L_i\)。对于每个查询 \(T_i\),需要找出在 \(T_i + 0.5\) 时刻仍在房间的人中的最大身高。关键观察是:一个人在 \(T_i + 0.5\) 时刻仍在房间 \(\Leftrightarrow L_i > T_i\)(因为 \(L_i\) 是整数,\(T_i + 0.5\) 时刻离开时间恰好为 \(L_i\) 的人已经离开)。因此问题转化为:对每个 \(T_i\),在所有满足 \(L_i > T_i\) 的人中求最大 \(H_i\)

  2. 算法选择

    • 排序 + 后缀最大值 + 整数二分:将人按离开时间升序排序,预处理后缀最大值数组,对每个查询二分查找第一个满足 \(L_i > T_i\) 的位置,\(O(1)\) 获取答案
    • 离线预处理:先排序并计算后缀最大值,将每次查询的回答优化至对数时间
  3. 关键步骤

    • 排序:将 \(N\) 个人按 \(L_i\) 升序排序(\(L_i\) 相同则按 \(H_i\) 升序)
    • 后缀最大值预处理:从后往前遍历,\(\text{maxH}[i] = \max(\text{maxH}[i+1], a[i].h)\),表示从第 \(i\) 个人到第 \(N\) 个人中的最大身高
    • 二分查找:对于查询值 \(t = T_i + 1\)(即 \(T_i + 0.5\) 的向上取整),找到第一个满足 \(a[pos].l > T_i\) 的位置 \(pos\)
    • 输出答案\(\text{maxH}[pos]\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(N \log N + Q \log N)\),排序 \(O(N \log N)\),预处理 \(O(N)\),每次查询二分 \(O(\log N)\)
    • 空间复杂度:\(O(N)\),存储人员信息数组和后缀最大值数组
  5. 排序 + 后缀最大值 + 二分的核心思想

    • 条件转化\(T_i + 0.5\) 时刻仍在房间 \(\Leftrightarrow L_i \geq T_i + 1\)(因为 \(L_i\) 为整数),将浮点时刻问题转化为整数比较
    • 排序降维:将二维查询(满足条件的人中求最大值)转化为一维问题:按离开时间排序后,满足 \(L_i > T_i\) 的人构成排序数组的一个后缀
    • 后缀最大值预处理:排序后,后缀最大值数组将"区间最值查询"优化为 \(O(1)\),配合二分查找实现高效回答
    • 二分定位后缀:利用排序数组的单调性,二分查找第一个满足条件的位置,将满足条件的集合定位为一个连续后缀
    • 适用于带时间约束的区间最值查询、离线预处理优化在线查询等场景

【算法标签】

普及- #整数二分

【代码详解】

#include <bits/stdc++.h>
using namespace std;
const int N = 300005;           // 最大节点数量
int n, q;                       // n: 高橋数量, q: 查询数量
int maxH[N];                    // 后缀最大值数组:maxH[i] 表示从第 i 个到第 n 个高橋中的最大身高
struct Node
{
    int h, l;                   // h: 身高, l: 离开时间
} a[N];                         // 存储所有高橋的信息

// 按离开时间升序排序,若离开时间相同则按身高升序
bool cmp(Node x, Node y)
{
    if (x.l != y.l) return x.l < y.l;
    return x.h < y.h;
}

// 二分查找判断:第 mid 个高橋的离开时间是否 >= x(即 T_i+0.5 分钟后是否仍在房间)
bool check(int x, int mid)
{
    if (a[mid].l >= x) return true;     // 仍在房间
    else return false;                  // 已离开
}

// 二分查找:找到第一个离开时间 >= x 的高橋的位置
int find(int x)
{
    int l = 1, r = n;
    while (l < r)
    {
        int mid = (l + r) / 2;
        if (check(x, mid))
            r = mid;                    // 第 mid 个仍在房间,答案在左半部分
        else
            l = mid + 1;                // 第 mid 个已离开,答案在右半部分
    }
    return l;
}

int main()
{
    cin >> n;                           // 读入高橋数量
    for (int i = 1; i <= n; i++)
        cin >> a[i].h >> a[i].l;       // 读入每个高橋的身高和离开时间

    sort(a + 1, a + n + 1, cmp);        // 按离开时间升序排序

    // 预处理后缀最大值:从后往前遍历,maxH[i] = max(a[i..n].h)
    for (int i = n; i >= 1; i--)
        maxH[i] = max(maxH[i + 1], a[i].h);

    cin >> q;                           // 读入查询数量
    while (q--)                         // 依次处理每个查询
    {
        int t;
        cin >> t;
        t = round(t + 0.5);             // 计算 T_i + 0.5 的整数表示(等价于向上取整)
        int pos = find(t);              // 二分查找第一个离开时间 >= t 的位置
        // cout << "t pos " << t << " " << pos << endl;
        cout << maxH[pos] << endl;      // 输出从 pos 开始到末尾的所有高橋中的最大身高
    }
    return 0;
}

【运行结果】

4
31 4
26 5
3 5
15 9
4
3 4 5 6
31
26
15
15
posted @ 2026-07-01 21:37  团爸讲算法  阅读(11)  评论(0)    收藏  举报