题解:洛谷 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
【核心思想】
-
问题分析:给定 \(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\)。
-
算法选择:
- 排序 + 后缀最大值 + 整数二分:将人按离开时间升序排序,预处理后缀最大值数组,对每个查询二分查找第一个满足 \(L_i > T_i\) 的位置,\(O(1)\) 获取答案
- 离线预处理:先排序并计算后缀最大值,将每次查询的回答优化至对数时间
-
关键步骤:
- 排序:将 \(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]\)
-
时间/空间复杂度:
- 时间复杂度:\(O(N \log N + Q \log N)\),排序 \(O(N \log N)\),预处理 \(O(N)\),每次查询二分 \(O(\log N)\)
- 空间复杂度:\(O(N)\),存储人员信息数组和后缀最大值数组
-
排序 + 后缀最大值 + 二分的核心思想:
- 条件转化:\(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
浙公网安备 33010602011771号