F - MST Query

F - MST Query

Problem Statement

You are given a weighted undirected connected graph G with N vertices and N1 edges, where vertices are numbered 1 to N and edges are numbered 1 to N1. Edge i connects vertices ai and bi with a weight of ci.

You are given Q queries to process sequentially. The i-th query is described as follows:

  • You are given integers ui,vi,wi. Add an edge with weight wi between vertices ui and vi in G. Then, print the sum of the weights of the edges in a minimum spanning tree of G.

Constraints

  • 2N2×105
  • 1Q2×105
  • 1ai<biN
  • 1ui<viN
  • 1ci,wi10
  • The graph is connected before processing the queries.
  • All input values are integers.

Input

The input is given from Standard Input in the following format:

N Q
a1 b1 c1

aN1 bN1 cN1
u1 v1 w1

uQ vQ wQ

Output

Print Q lines. The i-th line should contain the answer to the i-th query.


Sample Input 1

4 4
1 2 6
2 3 5
2 4 4
1 3 3
1 2 3
1 4 10
3 4 1

Sample Output 1

12
10
10
7

Here is the graph after adding the edge for each query. The edges included in the minimum spanning tree are colored red.


Sample Input 2

8 6
1 8 8
1 6 10
1 5 8
2 6 6
6 7 6
1 3 9
2 4 7
1 3 4
1 6 7
3 4 6
1 5 1
7 8 4
3 5 3

Sample Output 2

49
46
45
38
34
33

 

解题思路

  容易想到可以动态维护最小生成树,对于每个询问 (u,v,w),当插入这条边时必然会形成一个环,为了使得生成树最小,则需要在树中找到 uv 这条路径上最大边权对应的边,如果最大边权比 w 大则删除这条边,再插入边 (u,v)。LCT 可以实现上述的操作,但我没学过不会

  注意到边权非常小,我们可以换一种思路去思考这个问题。上面的做法是动态维护大小为 n1 的边集,而暴力的做法是直接往边集里加新边,每次跑一遍 Kruskal 求 MST。回想 Kruskal 算法,本质是按边权从小到大把不会构成环的边加到边集中,最后得到的 MST 的权重就是 ici,其中 ci 表示边集中边权 i 的数量。现在边权最大只有 10,显然可以直接去暴力计算这个结果,但问题是如何知道 ci

  每往边集加入一条边后,连通块的数量就会减 1。考虑把不构成环的权值小于 i 的边都加入后的连通块数量,记为 cnt[i1],再把不构成环的权值为 i 的边加入后的连通块数量,记为 cnt[i],那么边集中权值为 i 的边的数量就是 ci=cnt[i1]cnt[i]

  为此我们需要维护 10 个并查集,分别维护加入权值不超过 i 且不构成环的边所构成的连通块。每要次插入边 (u,v,w) 时,因此遍历 w10 所对应的并查集,如果 uv 不在同一个连通块内,则进行合并,对应并查集的连通块数量减 1

  AC 代码如下,时间复杂度为 O((n+m)W)

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 2e5 + 5, M = 15;

int fa[M][N], cnt[M];

int find(int *fa, int x) {
    return fa[x] == x ? fa[x] : fa[x] = find(fa, fa[x]);
}

int main() {
    int n, m;
    scanf("%d %d", &n, &m);
    for (int i = 0; i <= 10; i++) {
        iota(fa[i], fa[i] + n + 1, 0);
        cnt[i] = n;
    }
    for (int i = 0; i < n - 1; i++) {
        int u, v, w;
        scanf("%d %d %d", &u, &v, &w);
        for (int j = w; j <= 10; j++) {
            int a = find(fa[j], u), b = find(fa[j], v);
            if (a != b) {
                fa[j][a] = b;
                cnt[j]--;
            }
        }
    }
    while (m--) {
        int u, v, w;
        scanf("%d %d %d", &u, &v, &w);
        for (int j = w; j <= 10; j++) {
            int a = find(fa[j], u), b = find(fa[j], v);
            if (a != b) {
                fa[j][a] = b;
                cnt[j]--;
            }
        }
        int ret = 0;
        for (int i = 1; i <= 10; i++) {
            ret += (cnt[i - 1] - cnt[i]) * i;
        }
        printf("%d\n", ret);
    }
    
    return 0;
}

 

参考资料

  Editorial - Tokio Marine & Nichido Fire Insurance Programming Contest 2024(AtCoder Beginner Contest 355):https://atcoder.jp/contests/abc355/editorial/10072

  AtCoder Beginner Contest 355 - ~Lanly~ - 博客园:https://www.cnblogs.com/Lanly/p/18213969#f---mst-query-abc355-f

posted @   onlyblues  阅读(54)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
历史上的今天:
2023-05-27 股票买卖 V
2021-05-27 公路村村通
2021-05-27 旅游规划
2021-05-27 哈利·波特的考试
2021-05-27 列出连通集
2021-05-27 堆中的路径
2021-05-27 Root of AVL Tree
Web Analytics
点击右上角即可分享
微信分享提示