1 solutions
-
1
本题是一个经典的优化建图问题,线段树优化建图、利用贪心性质分析之后然后 dp 都可以,这里只介绍一种基于非负最短路特性的隐式松弛做法。
对于非负最短路,想要构成其最短路径树有一个关键的性质:每一个节点至多被松弛 1 次。
因此我们可以使用
set
或者区间染色并查集等数据结构,保存集合内尚未松弛的点。而从队列当中拿出一个已经松弛过的点之后,遍历其邻接且未松弛的点,将他们的最短距离确定,并加入队列即可。一个点遍历完之后,在集合中删掉这些松弛点,这样可以保证每一个点都只被遍历了 1 次。总复杂度 ,即便是
python3
也能轻松通过。#include <stdio.h> #include <string.h> #include <set> #include <queue> #include <algorithm> inline int rd() { int k = 0, f = 1; char s = getchar(); while (s < '0' || s > '9') f = (s == '-') ? 0 : f, s = getchar(); while (s >= '0' && s <= '9') k = (k << 1) + (k << 3) + (s ^ '0'), s = getchar(); return f ? k : -k; } inline void wr(int x) { if (x < 0) putchar('-'), x = -x; if (x > 9) wr(x / 10); putchar((x % 10) ^ '0'); } const int N = 100010; int n; int a[N], b[N], f[N]; bool vis[N]; std::set<int> s; std::queue<int> q; int main() { n = rd(); for (int i = 1; i <= n; ++i) a[i] = i - rd(), s.insert(i); for (int i = 1; i <= n; ++i) b[i] = rd(); memset(f, 0xff, (n + 1) << 2); q.push(1), f[1] = 0, s.erase(1), vis[1] = 1; while (q.size()) { int u = q.front(); q.pop(); auto st = s.lower_bound(std::min(n, u + 1)), cur = st, ed = s.lower_bound(std::min(n + 1, u + b[u] + 1)); while (cur != ed) { int v = a[*cur]; if (!vis[v]) f[v] = f[u] + 1, vis[v] = 1, q.push(v); ++cur; } s.erase(st, ed); } wr(f[n]); }
- 1
Information
- ID
- 43
- Time
- 500ms
- Memory
- 512MiB
- Difficulty
- 3
- Tags
- # Submissions
- 41
- Accepted
- 7
- Uploaded By