T5 旅行 (Day 2) 题解
T5 旅行 (Day 2) 题解
链接:click here
这道题有最大值加上最小值比较麻烦,于是考虑枚举最大值,然后逐个加边,查询最小瓶颈路,于是我们可以先把最小瓶颈树给跑出来,同时算出 $\text{dfs} $ 序,加入一条边时,如果它是树边,直接用并查集连接,如果没有和1相连暂时不更新,否则暴力遍历所有的节点,强行更新答案与最小瓶颈路。如果不是树边,就会将 \(u\) 到 \(\operatorname{LCA}(u,v)\) 和 \(v\) 到 \(\operatorname{LCA}(u,v)\) 上所有的点缩为一点,因为这形成了一个边双,这个节点的点权变为所有被缩点的点权和边权,可以再用一个并查集维护;如果非树边两个端点在同一结点(可以是缩完的点)中,那么直接更新点权即可,答案与最小瓶颈路使用两棵线段树维护即可。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 3e5 + 5;
const int K = 20;
struct DSU {
vector<int> fa;
int n;
DSU (int n) : n(n) {
fa.assign(n + 1, 0);
iota(fa.begin(), fa.end(), 0);
}
int find(int x) {
if (x == fa[x]) return x;
return fa[x] = find(fa[x]);
}
void unite(int u, int v) {
u = find(u), v = find(v);
if (u == v) return;
fa[v] = u;
}
};
#define ls(i) (tree[i].ch[0])
#define rs(i) (tree[i].ch[1])
struct node {
int mn = 1e12, tag = 1e12;
int ch[2];
void apply(int v) {
mn = min(mn, v);
tag = min(tag, v);
}
} tree[N * 40];
int ncnt = 0;
int root1, root2;
void pushdown(int i) {
if (tree[i].tag != 1e12) {
if (!ls(i)) ls(i) = ++ncnt;
if (!rs(i)) rs(i) = ++ncnt;
tree[ls(i)].apply(tree[i].tag);
tree[rs(i)].apply(tree[i].tag);
tree[i].tag = 1e12;
}
}
void update(int &i, int tl, int tr, int l, int r, int v) {
if (!i) i = ++ncnt;
if (l <= tl && tr <= r) {
tree[i].apply(v);
return;
}
int tm = tl + tr >> 1;
pushdown(i);
if (l <= tm)
update(ls(i), tl, tm, l, r, v);
if (r > tm)
update(rs(i), tm + 1, tr, l, r, v);
tree[i].mn = min(tree[ls(i)].mn, tree[rs(i)].mn);
}
void change(int &i, int tl, int tr, int pos, int v) {
if (!i) i = ++ncnt;
if (tl == tr) {
tree[i].mn = v;
return;
}
int tm = tl + tr >> 1;
pushdown(i);
if (pos <= tm)
change(ls(i), tl, tm, pos, v);
else
change(rs(i), tm + 1, tr, pos, v);
tree[i].mn = min(tree[ls(i)].mn, tree[rs(i)].mn);
}
int query(int i, int tl, int tr, int pos) {
if (!i) return 1e12;
if (tl == tr) {
return tree[i].mn;
}
int tm = tl + tr >> 1;
pushdown(i);
if (pos <= tm)
return query(ls(i), tl, tm, pos);
else
return query(rs(i), tm + 1, tr, pos);
}
vector<pair<int, int>> g[N];
struct Edge {
int u, v, w;
friend bool operator < (Edge x, Edge y) {
return x.w < y.w;
}
};
vector<Edge> edge, ne;
int n, m;
void kruskal() {
sort(edge.begin(), edge.end());
DSU dsu(n);
for (auto [u, v, w] : edge) {
if (dsu.find(u) != dsu.find(v)) {
dsu.unite(u, v);
g[u].push_back({v, w});
g[v].push_back({u, w});
ne.push_back({u, v, w});
}
}
}
int dfn[N], dcnt = 0, siz[N];
int dep[N];
int st[N][K], wf[N];
void dfs1(int u, int fa) {
dfn[u] = ++dcnt;
siz[u] = 1;
st[u][0] = fa;
dep[u] = dep[fa] + 1;
for (auto [v, w] : g[u]) {
if (v == fa) continue;
wf[v] = w;
dfs1(v, u);
siz[u] += siz[v];
}
}
void init_st() {
for (int i = 1; i < K; i++) {
for (int j = 1; j <= n; j++)
st[j][i] = st[st[j][i - 1]][i - 1];
}
}
int jump(int x, int k) {
for (int i = K - 1; i >= 0; i--) {
if (k >> i & 1) {
x = st[x][i];
}
}
return x;
}
int LCA(int u, int v) {
if (dep[u] > dep[v]) u = jump(u, dep[u] - dep[v]);
else v = jump(v, dep[v] - dep[u]);
if (u == v) return u;
for (int i = K - 1; i >= 0; i--) {
if (st[u][i] != st[v][i]) {
u = st[u][i];
v = st[v][i];
}
}
return st[u][0];
}
int val[N];
int bel[N];
int ans[N];
void dfs(int u, int fa, int c, int mn, DSU &dsu1, int W) {
mn = min(mn, val[u]);
mn = min(mn, wf[u]);
change(root1, 1, n, dfn[u], mn + W);
change(root2, 1, n, dfn[u], mn);
for (auto [v, w] : g[u]) {
if (v == fa) continue;
if (dsu1.find(v) == c) {
dfs(v, u, c, mn, dsu1, W);
}
}
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++)
val[i] = 1e12;
for (int i = 1; i <= m; i++) {
int u, v, w;
cin >> u >> v >> w;
edge.push_back({u, v, w});
}
kruskal();
dfs1(1, 0);
init_st();
DSU dsu1(n), dsu2(n);
for (auto [u, v, w] : edge) {
if (dsu1.find(u) == dsu1.find(v)) {
if (dsu2.find(u) == dsu2.find(v)) {
int lca = dsu2.find(u);
val[dsu2.find(u)] = min(val[dsu2.find(u)], w);
update(root1, 1, n, dfn[lca], dfn[lca] + siz[lca] - 1, val[lca] + w);
update(root2, 1, n, dfn[lca], dfn[lca] + siz[lca] - 1, val[lca]);
continue;
}
int lca = dsu2.find(LCA(u, v));
for (int x = dsu2.find(u); x != lca; x = dsu2.find(st[x][0])) {
dsu2.unite(lca, x);
val[lca] = min(val[lca], val[x]);
val[lca] = min(val[lca], wf[x]);
}
for (int x = dsu2.find(v); x != lca; x = dsu2.find(st[x][0])) {
dsu2.unite(lca, x);
val[lca] = min(val[lca], val[x]);
val[lca] = min(val[lca], wf[x]);
}
update(root1, 1, n, dfn[lca], dfn[lca] + siz[lca] - 1, val[lca] + w);
update(root2, 1, n, dfn[lca], dfn[lca] + siz[lca] - 1, val[lca]);
}
else {
if (dsu1.find(u) == 1) {
int mn = query(root2, 1, n, dfn[u]);
dfs(dsu1.find(v), 0, dsu1.find(v), mn, dsu1, w);
dsu1.unite(u, v);
}
else if (dsu1.find(v) == 1) {
swap(u, v);
int mn = query(root2, 1, n, dfn[u]);
dfs(dsu1.find(v), 0, dsu1.find(v), mn, dsu1, w);
dsu1.unite(u, v);
}
else {
if (dfn[u] < dfn[v]) dsu1.unite(u, v);
else dsu1.unite(v, u);
}
}
}
for (int i = 2; i <= n; i++)
cout << query(root1, 1, n, dfn[i]) << '\n';
return 0;
}

浙公网安备 33010602011771号