CF827D Best Edge Weight 题解
树上倍增+可并堆。
把原图的 MST 建出来,分别考虑非树边和树边的答案。
对于非树边
树上倍增维护路径最大值即可。
对于树边
即对每条非树边在 MST 上的路径,对这条非树边的权值 check min。
用可并堆维护 check min 操作。
具体地,对每条非树边
从下往上合并每个点的堆,合并到
这些操作中,只有
此时的堆顶即为
#include <cstdio>
#include <algorithm>
#include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace std;
struct E
{
int v, w, t;
} e[400050];
struct S
{
int u, v, w, i;
} g[200050];
__gnu_pbds::priority_queue<pair<int, int>, greater<pair<int, int>>> q[200050];
int n, m, c, z[200050], r[200050], d[200050], h[200050], f[20][200050], w[20][200050];
bool o[200050];
bool C(S a, S b) { return a.w < b.w; }
bool R(S a, S b) { return a.i < b.i; }
int F(int x) { return x == z[x] ? x : z[x] = F(z[x]); }
void A(int u, int v, int w) { e[++c] = {v, w, h[u]}, h[u] = c; }
void D(int u)
{
for (int i = h[u], v; i; i = e[i].t)
if (!d[v = e[i].v])
{
w[0][v] = e[i].w;
d[v] = d[f[0][v] = u] + 1;
for (int j = 1; f[j - 1][v]; ++j)
f[j][v] = f[j - 1][f[j - 1][v]], w[j][v] = max(w[j - 1][v], w[j - 1][f[j - 1][v]]);
D(v);
}
}
int L(int u, int v)
{
if (d[u] < d[v])
swap(u, v);
while (d[u] > d[v])
u = f[__lg(d[u] - d[v])][u];
if (u == v)
return u;
for (int k = __lg(d[u]); k >= 0; --k)
if (f[k][u] != f[k][v])
u = f[k][u], v = f[k][v];
return f[0][u];
}
int Q(int u, int v)
{
int q = 0;
if (d[u] < d[v])
swap(u, v);
while (d[u] > d[v])
q = max(q, w[__lg(d[u] - d[v])][u]), u = f[__lg(d[u] - d[v])][u];
if (u == v)
return q;
for (int k = __lg(d[u]); k >= 0; --k)
if (f[k][u] != f[k][v])
q = max({q, w[k][u], w[k][v]}), u = f[k][u], v = f[k][v];
return max({q, w[0][u], w[0][v]});
}
void M(int u, int k)
{
for (int i = h[u], v; i; i = e[i].t)
if ((v = e[i].v) != k)
M(v, u), q[u].join(q[v]);
while (!q[u].empty() && d[q[u].top().second] >= d[u])
q[u].pop();
if (!q[u].empty())
r[u] = q[u].top().first - 1;
else
r[u] = -1;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
z[i] = i;
for (int i = 0; i < m; ++i)
scanf("%d%d%d", &g[i].u, &g[i].v, &g[i].w), g[i].i = i;
sort(g, g + m, C);
for (int i = 0, u, v, p = 0; i < m; ++i)
if ((u = F(g[i].u)) != (v = F(g[i].v)))
{
z[u] = v;
o[g[i].i] = 1;
A(g[i].u, g[i].v, g[i].w);
A(g[i].v, g[i].u, g[i].w);
if (++p == n - 1)
break;
}
D(d[1] = 1);
for (int i = 0, l; i < m; ++i)
if (!o[g[i].i])
q[g[i].u].push({g[i].w, l = L(g[i].u, g[i].v)}), q[g[i].v].push({g[i].w, l});
M(1, 0);
sort(g, g + m, R);
for (int i = 0; i < m; ++i)
if (o[i])
printf("%d ", r[d[g[i].u] > d[g[i].v] ? g[i].u : g[i].v]);
else
printf("%d ", Q(g[i].u, g[i].v) - 1);
return 0;
}
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具