1 条题解

  • 0
    @ 2023-1-29 14:30:57
    #include <bits/stdc++.h>
    #define int long long
    using namespace std;
    const int MAXN = 500000;
    const int MAXM = 500000;
    // 传入两个最大次大值,返回四个数的最大次大值
    pair<int, int> getMaxW(pair<int, int> a, pair<int, int> b)
    {
        if (a.first == b.first)
            return make_pair(a.first, max(a.second, b.second));
        if (a.first > b.first)
            return make_pair(a.first, max(a.second, b.first));
        if (a.first < b.first)
            return make_pair(b.first, max(a.first, b.second));
    }
    //-----------封装LCA
    struct LCA
    {
        int n, root;             // 点数、询问个数、根节点
        vector<int> e[MAXN + 5]; // 存树
        int fa[MAXN + 5];
        int maxDep, dep[MAXN + 5];
        int lg2[MAXN + 5];             // 替代 log2(i)
        int dp[MAXN][35];              // i号点的 2^j 层祖先
        vector<int> ew[MAXN + 5];      // 树的边权 -----
        pair<int, int> maxW[MAXN][35]; // i号点的 2^j 层最大次大边权-----
        // 图的初始化
        void init(int _n, int _root)
        {
            n = _n;
            root = _root;
            for (int i = 1; i <= n; i++)
                e[i].clear();
        }
        // 加边
        void addEdge(int u, int v, int w)
        {
            e[u].push_back(v);
            e[v].push_back(u);
            ew[u].push_back(w); //-----
            ew[v].push_back(w); //-----
        }
        // dfs 得到父子关系、深度
        void dfs(int u, int father)
        {
            fa[u] = father;
            for (int i = 0; i < e[u].size(); i++)
            {
                int v = e[u][i];
                int w = ew[u][i]; //-----
                if (v == father)
                    continue;
                dep[v] = dep[u] + 1;
                maxW[v][0] = make_pair(w, -1); //------
                maxDep = max(maxDep, dep[v]);
                dfs(v, u);
            }
        }
        // lca 的初始化
        void init_lca()
        {
            // 预处理:最大层数 maxDep、每个点的深度、记录父节点、log2[]、dp数组
            dep[root] = 1;
            maxDep = 1;
            dfs(root, 0);
            lg2[1] = 0;
            for (int i = 2; i <= n; i++)
                // i == 2^(log2(i-1)+1)
                if (i == (1 << (lg2[i - 1] + 1)))
                    lg2[i] = lg2[i - 1] + 1;
                else
                    lg2[i] = lg2[i - 1];
            for (int j = 0; j <= lg2[n]; j++)
            {
                for (int i = 1; i <= n; i++)
                {
                    // 求解 dp[i][j]
                    if (j == 0)
                        dp[i][j] = fa[i];
                    else
                        dp[i][j] = dp[dp[i][j - 1]][j - 1];
                    // 求解 maxW[i][j]
                    if (j > 0)
                        maxW[i][j] = getMaxW(maxW[i][j - 1],
                                             maxW[dp[i][j - 1]][j - 1]);
                }
            }
        }
        // 查询两个点的lca
        int lca(int u, int v)
        {
            if (dep[u] > dep[v])
                swap(u, v); // 让u的高度不低于v
            if (u == v)
                return u;
            // 把 v 提到与 u 同样高度
            for (int j = lg2[n]; j >= 0; j--)
                if ((1 << j) <= dep[v] - dep[u])
                {
                    v = dp[v][j];
                }
            if (u == v)
                return u;
            // 找lca
            for (int j = lg2[n]; j >= 0; j--)
                if (dp[v][j] != dp[u][j])
                {
                    v = dp[v][j],
                    u = dp[u][j];
                }
            return dp[u][0];
        }
        pair<int, int> queryMaxW(int u, int v)
        {
            int uv = lca(u, v);
            pair<int, int> res = make_pair(-1, -1);
            // 把 u 提到与 uv 同样高度
            for (int j = lg2[n]; j >= 0; j--)
                if ((1 << j) <= dep[u] - dep[uv])
                {
                    res = getMaxW(res, maxW[u][j]);
                    u = dp[u][j];
                }
            // 把 v 提到与 uv 同样高度
            for (int j = lg2[n]; j >= 0; j--)
                if ((1 << j) <= dep[v] - dep[uv])
                {
                    res = getMaxW(res, maxW[v][j]);
                    v = dp[v][j];
                }
            return res;
        }
    } lca;
    //-----------封装Kruskal
    struct kEdge
    {
        int u, v, w;
        bool cho; // 是否被选中了
    };
    bool operator<(const kEdge &a, const kEdge &b)
    {
        return a.w < b.w;
    }
    struct Kruskal
    {
        int n, m, ans;
        vector<kEdge> e; // 存所有的边
        int fa[MAXN + 5];
        int findFa(int x)
        {
            if (x == fa[x])
                return x;
            return fa[x] = findFa(fa[x]);
        }
        void init(int _n, int _m)
        {
            n = _n;
            m = _m;
            ans = 0;
            for (int i = 1; i <= n; i++)
                fa[i] = i;
        }
        void addEdge(int u, int v, int w)
        {
            e.push_back((kEdge){u, v, w, false});
        }
        void run()
        {
            sort(e.begin(), e.end());
            for (int i = 0; i < e.size(); i++)
            {
                int u = e[i].u;
                int v = e[i].v;
                int w = e[i].w;
                int fU = findFa(u);
                int fV = findFa(v);
                if (fU == fV)
                    continue;
                e[i].cho = true; // 这条边被选择了
                ans += e[i].w;
                fa[fU] = fV;
            }
        }
    } kruskal;
    signed main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        int n, m;
        cin >> n >> m;
        kruskal.init(n, m);
        for (int i = 1; i <= m; i++)
        {
            int u, v, w;
            cin >> u >> v >> w;
            kruskal.addEdge(u, v, w);
        }
        kruskal.run();
        lca.init(n, 1);
        for (int i = 0; i < kruskal.e.size(); i++)
            if (kruskal.e[i].cho)
                lca.addEdge(kruskal.e[i].u, kruskal.e[i].v, kruskal.e[i].w);
        lca.init_lca();
    
        int ans = 1e18;
        for (int i = 0; i < kruskal.e.size(); i++)
            if (!kruskal.e[i].cho)
            {
                pair<int, int> maxW = lca.queryMaxW(kruskal.e[i].u, kruskal.e[i].v);
                int m1 = maxW.first;
                int m2 = maxW.second;
                if (m1 == kruskal.e[i].w && m2 != -1)
                    ans = min(ans, kruskal.ans - m2 + kruskal.e[i].w);
                else if (m1 != kruskal.e[i].w && m1 != -1)
                    ans = min(ans, kruskal.ans - m1 + kruskal.e[i].w);
            }
        cout << ans << "\n";
        return 0;
    }
    
    
    • 1

    信息

    ID
    785
    时间
    1000ms
    内存
    512MiB
    难度
    9
    标签
    递交数
    30
    已通过
    4
    上传者