1 solutions
-
0
Guest MOD
-
-1
类似最小生成树,考虑从小到大加边,如果加完一条边之后, 这两个点所在的 连通块,只需要再加一条边就可以连通,那么这条边就是第二小的,也就是答案。 接着考虑如何维护这一过程。对于一个连通块 ,记与这个连通块有边相连的点为 。考虑启发式合并,对于两个连通块 合并后,那么可能 中的点和 有 边相连了, 中的点和 有边相连了。如果直接遍历 N(u) 和 中的点,那么时间复杂度是显然不对的。 我们可以做的是,遍历 的所有点,然后查询是不是 相连,然后遍历 里面的所有询问,看是不是在 之中即可。这样只需要遍历其中一部分的信息,所以 可以启发式合并。每次我们按 大小加询问个数比较,然后遍历小的部分,启发式合并即可。合并完之后,更新一下合并之后的连通块的邻居和询问信息。 时间复杂度是 的。
#include <bits/stdc++.h> using namespace std; #define N 400005 #define pb push_back int fa[N]; struct node { int x, y, z; } b[N]; int ans[N], n, m, Q; set<array<int, 2>> q[N]; set<int> e[N]; int get(int x) { if (fa[x] == x) return x; return fa[x] = get(fa[x]); } inline bool cmp(node x, node y) { return x.z < y.z; } void combine(int x, int y, int val) { for (auto u : e[x]) { while (1) { auto it = q[y].lower_bound({u, -1}); if (it == q[y].end() || (*it)[0] != u) break; int id = (*it)[1]; ans[id] = val; assert(q[y].count({u, id})); assert(q[u].count({y, id})); q[y].erase(it); q[u].erase({y, id}); } } vector<array<int, 2>> delq; for (auto u : q[x]) { if (e[y].count(u[0])) { ans[u[1]] = val; q[u[0]].erase({x, u[1]}); delq.pb(u); } } for (auto u : delq) q[x].erase(u); fa[x] = y; for (auto v : e[x]) { assert(e[v].count(x)); e[v].erase(x); if (v != y) { e[v].insert(y); e[y].insert(v); } } e[x].clear(); for (auto v : q[x]) { assert(v[0] != y); assert(q[v[0]].count({x, v[1]})); q[v[0]].erase({x, v[1]}); q[v[0]].insert({y, v[1]}); q[y].insert({v[0], v[1]}); } q[x].clear(); } int main() { freopen("path.in", "r", stdin); freopen("path.out", "w", stdout); scanf("%d%d%d", &n, &m, &Q); for (int i = 1; i <= n; i++) e[i].clear(), q[i].clear(); for (int i = 1; i <= m; i++) { scanf("%d%d%d", &b[i].x, &b[i].y, &b[i].z); e[b[i].x].insert(b[i].y); e[b[i].y].insert(b[i].x); } for (int i = 1; i <= n; i++) fa[i] = i; sort(b + 1, b + 1 + m, cmp); for (int i = 1; i <= Q; i++) { ans[i] = 0; int x, y; scanf("%d%d", &x, &y); if (e[x].count(y)) { ans[i] = 1; continue; } q[x].insert({y, i}); q[y].insert({x, i}); } for (int i = 1; i <= m; i++) { b[i].x = get(b[i].x), b[i].y = get(b[i].y); if (b[i].x == b[i].y) continue; if (q[b[i].x].size() + e[b[i].x].size() > q[b[i].y].size() + e[b[i].y].size()) swap(b[i].x, b[i].y); combine(b[i].x, b[i].y, b[i].z + 1); } for (int i = 1; i <= Q; i++) printf("%d\n", ans[i] - 1); }
- 1
Information
- ID
- 315
- Time
- 1000ms
- Memory
- 256MiB
- Difficulty
- 10
- Tags
- # Submissions
- 11
- Accepted
- 0
- Uploaded By