1 条题解
-
0
自动搬运
来自洛谷,原作者为

Alex_Wei
**搬运于
2025-08-24 22:50:02,当前版本为作者最后更新于2023-09-10 17:20:57,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
P9604 [IOI2023] 超车
如果 被 堵住了,那么 的速度一定大于 :如果 ,则存在 使得 被 堵住了,否则 不会把 堵住。简单地说,如果车辆 从 到 的过程中并非全速行驶(),那么存在 使得 到达 的时间严格早于 (),且 到达 的时间严格晚于 (),这说明 的速度小于 ()。
这说明,在考虑 到达每个调度站的时间的时候,速度不小于 的车辆不产生影响:如果 被堵住,那么 所在的 “堵车集团” 一定是被它们当中速度最慢的车堵住的,可以认为 被这辆车堵住了,而如果这辆车的速度和 相同,那么可以认为 是在正常行驶,没有被堵住。因为我们只关心 到达调度站的时间,所以先忽略掉所有速度不小于 的车,即 的所有 。以下设 。
我们尝试对所有 和 求出 。首先有 。在 时,直接按照题目给出的方式暴力转移的时间复杂度是 ,无法接受。按照 从小到大枚举 ,同时维护所有 的 的最大值即可做到 。如果 相同的 按照速度从快到慢枚举,则有先枚举的 先到达 的性质:后到达 的车不会比先到达 的车早到达 ,而同一时刻到达 的车,排在前面的速度更快,更早到达 。在这种枚举顺序下,我们可以认为 到达 的时间受到的限制是比它先枚举的 到达 的 实际时间 ,而非 期望时间 (因为限制到 的 一定满足实际时间等于期望时间),也就是令 之后,对 做 "前缀" 。
算出 之后,我们有 回答单次询问的做法:二分求出 在 中的位置,可以直接算出 。而 的速度大于其它车辆,所以 不会对 产生任何影响。可以获得 分。
为了做到单组询问优于 ,我们尝试预处理所有可能的询问的答案。如果不这样做,对每组询问直接模拟,则无论如何都需要至少 的时间复杂度。
考虑每个 的限制:如果 ,那么 对 取 。这样问题就变成了:查询第一个权值大于 的位置,全局加法,区间取 。注意在 的过程中,区间 要在查询完所有第一个权值大于某个值的位置之后才能进行。全局加法可以直接打标记,剩下部分可以使用动态开点线段树维护,下标表示出发时间,值表示到达当前调度站的时间。
这个做法不仅难写,而且值域大空间紧。一个常用技巧是:根据单调性,将区间取 变成区间赋值。我们算出赋值的具体情况。不妨设 是按照 的顺序枚举的(根据分析,对 有 且 ),那么对于一段极长的 相同的 连续段 :
- 它相当于将 值 区间 对 取 。
- 因为若 ,那么 一定大于 ,所以 值 区间缩小为 。这一步是为了防止原来较大的值被赋小了。
- 因为若 且 ,那么 会和更大的值取 ,所以 值 区间缩小为 $(t_{l, j - 1}, \min(t_{l, j} - X(S_j - S_{j - 1}), t_{r + 1, j - 1})]$。注意当 时忽略 的第二项。这一步是为了防止不同的取 操作之间变成赋值之后互相干扰。
最终得到的所有操作的值区间两两无交,可以用维护值区间以及对应下标区间的 set 维护(ODT)。查询时直接二分即可。
时间复杂度 。
#include <bits/stdc++.h> using namespace std; using ll = long long; constexpr int MAXN = 1e3 + 5; constexpr int MAXM = 1e3 + 5; constexpr ll inf = 2e18; ll delt, f[MAXN][MAXM]; struct oper {ll l, r, v;}; struct itv { ll l, r, _l, _r; bool operator < (const itv &z) const { if(l != z.l) return l < z.l; if(r != z.r) return r < z.r; return _l < z._l; } }; set<itv> s; vector<itv> res; void init(int L, int N, vector<ll> T, vector<int> W, int X, int M, vector<int> S) { for(int i = 0; i < N; i++) { if(W[i] <= X) { W.erase(W.begin() + i); T.erase(T.begin() + i); N--, i--; } } for(int i = 0; i < N; i++) f[i][0] = T[i]; s.insert({-inf, inf, -inf, inf}); for(int t = 1; t < M; t++) { vector<int> id(N); for(int i = 0; i < N; i++) id[i] = i; sort(id.begin(), id.end(), [&](int x, int y) { if(f[x][t - 1] != f[y][t - 1]) return f[x][t - 1] < f[y][t - 1]; return W[x] < W[y]; }); ll d = S[t] - S[t - 1]; for(int i = 0; i < N; i++) { f[id[i]][t] = f[id[i]][t - 1] + W[id[i]] * d; if(i) f[id[i]][t] = max(f[id[i]][t], f[id[i - 1]][t]); } auto split = [&](ll p) { auto pt = --s.lower_bound({p + 1, -inf}); if(pt->l == p || pt->r < p) return; s.insert({pt->l, p - 1, pt->l, p - 1}); s.insert({p, pt->r, p, pt->r}); s.erase(pt); }; ll nxt = delt + X * d; vector<itv> add; for(int i = 0; i < N; ) { int j = i; while(j < N && f[id[j]][t] == f[id[i]][t]) j++; if(W[i] > X) { ll st = f[id[i]][t - 1] + 1 - delt; ll ed = min(f[id[i]][t] - X * d, j < N ? f[id[j]][t - 1] : inf) - delt; ll p = f[id[i]][t] - nxt; ll L = -inf, R = -1; split(st), split(ed + 1); while(1) { auto pt = s.lower_bound({st, -inf}); if(pt == s.end() || pt->l > ed) break; if(L == -inf) L = pt->_l; R = pt->_r; s.erase(pt); } if(L != -inf) add.push_back({p, p, L, R}); } i = j; } for(itv it : add) s.insert(it); delt = nxt; } for(itv it : s) res.push_back(it); } ll arrival_time(ll Y) { int l = 0, r = res.size() - 1; while(l < r) { int m = l + r + 2 >> 1; if(res[m]._l <= Y) l = m; else r = m - 1; } if(res[l].l < res[l].r) return Y + delt; return res[l].l + delt; }
- 1
信息
- ID
- 9184
- 时间
- 2500ms
- 内存
- 2048MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者