hetao 国庆

Day 5

T3

第一次模拟赛切紫喵(*2700),这里有

(开玩笑)

Solution

Subtask 1 可能比较具有启发性。

每个人只关心:每条路径上的最大值。我们要让这个值最小。所以容易发现他们只会在最小瓶颈树上走。

由于 MST 一定是最小瓶颈树,所以我们跑 kruskal 然后把树建出来。

此时边分为两类:

  • 非树边:
    • 考虑 \((u, v)\) 这条边,记 \(mx\) 为树上 \((u, v)\) 路径上边权的最大值。
      • 那么这条边的边权如果 \(< x\) 那么他就会代替树上的一条边。
      • 如果边权 \(= x\) 则他也可能成为树边。
    • 所以这条边的边权至少为 \(mx + 1\)
  • 树边:
    • 考虑我们可以有哪些边来替代这条树边 \((u, v)\)
      • 考虑添加一条非树边 \((u, v)\) 进来,则你可以把树上 \((u, v)\) 路径上的边随意删一个。
      • 所以这条边可以覆盖 \((u, v)\) 这条路径上的边。
    • 所以我们这条边的边权至少为可以覆盖到这条边的边边权的最小值。

那对于非树边你就可以树上倍增维护路径最大值。

对于树边你就可以按边权从大到小排序,然后树剖做区间覆盖。查询单点查就行。

Code

#include <bits/stdc++.h>

using namespace std;

const int N = 2e5 + 10, inf = 0x3f3f3f3f;

int n, m, p[N], dep[N], f[19][N], z[19][N], son[N], top[N], dfn[N], cnt, sz[N], ans[N];
struct edge { int u, v, w, id; bool ok; } e[N];
vector<pair<int, int>> g[N];

void dfs(int u, int fa)
{
    dep[u] = dep[f[0][u] = fa] + 1;
    sz[u] = 1;
    for (auto t : g[u]) {
        int v = t.first, w = t.second;
        if (v == fa) continue;
        z[0][v] = w;
        dfs(v, u); sz[u] += sz[v];
        if (sz[v] > sz[son[u]]) son[u] = v;
    }
}

void dfs1(int u, int t)
{
    top[u] = t;
    dfn[u] = ++cnt;
    if (son[u]) dfs1(son[u], t);
    for (auto k : g[u]) {
        int v = k.first;
        if (v != f[0][u] && v != son[u]) dfs1(v, v);
    }
}

int lca(int x, int y)
{
    int ans = 0;
    if (dep[x] < dep[y]) swap(x, y);
    for (int i = 18; i >= 0; i--) if (dep[f[i][x]] >= dep[y]) ans = max(ans, z[i][x]), x = f[i][x];
    if (x == y) return ans;
    for (int i = 18; i >= 0; i--) {
        if (f[i][x] != f[i][y]) {
            ans = max(ans, max(z[i][x], z[i][y]));
            x = f[i][x], y = f[i][y];
        }
    }
    ans = max(ans, max(z[0][x], z[0][y]));
    return ans;
}

int fifa(int x) { return p[x] == x ? p[x] : p[x] = fifa(p[x]); }

bool merge(int x, int y)
{
    x = fifa(x), y = fifa(y);
    if (x == y) return false;
    p[x] = y;
    return true;
}

int tr[N << 2], tag[N << 2];

#define ls (rt << 1)
#define rs (rt << 1 | 1)
#define mid (l + r) / 2

void pushup(int rt) { tr[rt] = min(tr[ls], tr[rs]); }

void pushdown(int rt)
{
    int &u = tag[rt];
    if (!u) return;
    tr[ls] = tr[rs] = tag[ls] = tag[rs] = u;
    u = 0;
}

void update(int rt, int l, int r, int sp, int ep, int v)
{
    if (sp <= l && r <= ep) return tr[rt] = tag[rt] = v, void();
    pushdown(rt);
    if (sp <= mid) update(ls, l, mid, sp, ep, v);
    if (ep > mid) update(rs, mid + 1, r, sp, ep, v);
    pushup(rt);
}

int query(int rt, int l, int r, int p)
{
    if (l == r) return tr[rt];
    pushdown(rt);
    if (p <= mid) return query(ls, l, mid, p);
    return query(rs, mid + 1, r, p);
}

void addpath(int x, int y, int w)
{
    while (top[x] != top[y]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        update(1, 1, n, dfn[top[x]], dfn[x], w);
        x = f[0][top[x]];
    }
    if (dfn[x] > dfn[y]) swap(x, y);
    update(1, 1, n, dfn[x] + 1, dfn[y], w);
}

void kruskal()
{
    for (int i = 1; i <= n; i++) p[i] = i;
    sort (e + 1, e + m + 1, [&](edge x, edge y) { return x.w < y.w; });
    for (int i = 1; i <= m; i++) {
        int u = e[i].u, v = e[i].v, w = e[i].w;
        if (merge(u, v)) {
            e[i].ok = 1;
            g[u].emplace_back(v, w);
            g[v].emplace_back(u, w);
        }
    }
}

int main()
{
    freopen("skyline.in", "r", stdin);
    freopen("skyline.out", "w", stdout);
    cin.tie(0)->ios::sync_with_stdio(false);
    cin >> n >> m;
    for (int i = 1; i <= m; i++) {
        int u, v, w; cin >> u >> v >> w;
        e[i] = (edge){ u, v, w, i, 0 };
    }
    kruskal();
    dfs(1, 0), dfs1(1, 1);
    for (int j = 1; j <= 18; j++)
        for (int i = 1; i <= n; i++) 
            f[j][i] = f[j - 1][f[j - 1][i]], z[j][i] = max(z[j - 1][i], z[j - 1][f[j - 1][i]]);
    for (int i = 1; i <= 4 * n; i++) tr[i] = inf, tag[i] = 0;
    for (int i = m; i >= 1; i--) {
        if (e[i].ok) continue;
        addpath(e[i].u, e[i].v, e[i].w);
    }
    for (int i = 1; i <= m; i++) {
        if (e[i].ok) {
            ans[e[i].id] = query(1, 1, n, dfn[(dep[e[i].u] > dep[e[i].v] ? e[i].u : e[i].v)]);
        } else {
            ans[e[i].id] = lca(e[i].u, e[i].v);
        }
    }
    for (int i = 1; i <= m; i++) cout << (ans[i] == inf ? -1 : ans[i] + 1) << " ";
    return 0;
}
posted @ 2025-10-06 14:31  Dtwww  阅读(18)  评论(0)    收藏  举报