[APIO2019]桥梁
作者:互联网
- 给定边带权的无向图 \((V,E)\)。\(q\) 次操作,改变一条边的权值或者询问从 \(s_i\) 出发只走权值大于等于 \(w_i\) 的边能够到达的点数。
- \(|V| \leq 5 \times 10^4, |E|, q \leq 10^5\) 。
分别考虑涉及修改和不涉及修改的边:
- 对于不涉及修改的边,将询问从大到小排序,然后从大到小加边用并查集维护联通块。这部分是 \(O(|E| \log |E| + q \log q)\) 的。
- 对于涉及修改的边,每次询问暴力访问询问之前的修改,满足条件就加入并查集。这部分是 \(O(q^2)\) 的。
将操作分块,设块大小为 \(S\),第一部分变为 \(O(|E|\log |E| + S \log S)\),第二部分变为 \(O(S^2)\)。
总复杂度 \(O(\frac qS|E|\log|E|+q\log S + qS)\),基本不等式大概算一下块大小,卡常。
#include <bits/stdc++.h>
#define dbg(...) std::cerr << "\033[32;1m", fprintf(stderr, __VA_ARGS__), std::cerr << "\033[0m"
template <class T, class U>
inline bool smin(T &x, const U &y) { return y < x ? x = y, 1 : 0; }
template <class T, class U>
inline bool smax(T &x, const U &y) { return x < y ? x = y, 1 : 0; }
using LL = long long;
using PII = std::pair<int, int>;
constexpr int N(5e4 + 5), S(500);
int fa[N], siz[N];
int find(int x) {
while (fa[x] != x) x = fa[x];
return x;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, m, q;
std::cin >> n >> m;
std::vector<std::array<int, 3>> e(m);
for (auto &[x, y, z] : e) std::cin >> x >> y >> z;
std::vector<int> eq(m);
std::iota(eq.begin(), eq.end(), 0);
auto cmp_edge = [&](int i, int j) { return e[i][2] > e[j][2]; };
std::sort(eq.begin(), eq.end(), cmp_edge);
std::cin >> q;
for (int i = 0; i < q; i += S) {
std::vector<std::array<int, 3>> a, b;
std::vector<char> vis(m);
for (int j = 0; j < S && i + j < q; j++) {
int t, x, y;
std::cin >> t >> x >> y;
if (t == 1) {
vis[--x] = 1;
a.push_back({ j, x, y });
} else {
b.push_back({ j, x, y });
}
(t == 1 ? a : b).push_back({ j, x, y });
}
std::sort(b.begin(), b.end(), [](const auto &x, const auto &y) { return x[2] > y[2]; });
std::vector<int> c, d, ans(a.size() + b.size());
for (int j = 0; j < m; j++) {
if (!vis[eq[j]]) {
c.push_back(eq[j]);
} else {
d.push_back(eq[j]);
}
}
std::iota(fa, fa + n + 1, 0);
std::fill(siz, siz + n + 1, 1);
auto p = c.begin();
for (auto &[t, s, w] : b) {
for (; p != c.end() && e[*p][2] >= w; p++) {
int x = find(e[*p][0]), y = find(e[*p][1]);
if (x == y) continue;
if (siz[x] > siz[y]) std::swap(x, y);
fa[x] = y, siz[y] += siz[x];
}
std::vector<int> pre(d.size());
for (int j = 0; j < d.size(); j++) {
pre[j] = e[d[j]][2];
}
for (auto &[tt, x, y] : a) {
if (tt > t) continue;
e[x][2] = y;
}
std::vector<std::array<int, 3>> v;
for (int j : d) {
if (e[j][2] >= w) {
int x = find(e[j][0]), y = find(e[j][1]);
if (x == y) continue;
if (siz[x] > siz[y]) std::swap(x, y);
v.push_back({ x, y, fa[x] });
fa[x] = y, siz[y] += siz[x];
}
}
ans[t] = siz[find(s)];
while (!v.empty()) {
auto &[x, y, z] = v.back();
fa[x] = z, siz[y] -= siz[x];
v.pop_back();
}
for (int j = 0; j < d.size(); j++) {
e[d[j]][2] = pre[j];
}
}
for (int i : ans) if (i) std::cout << i << "\n";
for (auto &[t, x, y] : a) e[x][2] = y;
std::sort(d.begin(), d.end(), cmp_edge);
std::merge(c.begin(), c.end(), d.begin(), d.end(), eq.begin(), cmp_edge);
}
return 0;
}
标签:std,APIO2019,int,siz,桥梁,fa,auto,eq 来源: https://www.cnblogs.com/HolyK/p/14332957.html