知识点:最小生成树,离线
这个题的做法是离线思想+最小生成树,题目给的询问,我们可以先输入进来排序,然后按照大小顺序来解决这些询问,然后每次询问前,都把小于这个询问的最小生成树的边连接了,因为题目问的是有多少对点的最小路径最大值大于等于某个数,把小于等于这个数的最小生成树的边连接了之后,那么点的对数就是各个连通块之间来统计,但是这样太麻烦,这里的做法是从初始值减,每连接一条边,就减去这两个连通块对答案的贡献,连个连通块对答案的贡献是两个连通块的个数相乘再乘以2,这个题目给的有提示,只要想清楚这个,这个题最后查询阶段就可以线性遍历解决了
#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 5, M = 5e5 + 5;
struct edge {
int u, v, w;
};
int fa[N], d[N], b[N * 10];
edge e[M];
pair<int, int> a[N * 10];
int get(int x) {
if (x == fa[x]) return x;
return fa[x] = get(fa[x]);
}
bool cmp(edge a, edge b) {
return a.w < b.w;
}
int main() {
int n, m;
while (cin >> n >> m) {
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
}
int q;
cin >> q;
for (int i = 1; i <= q; i++) {
int x;
scanf("%d", &x);
a[i] = make_pair(x, i);
}
sort(a + 1, a + q + 1);
sort(e + 1, e + m + 1, cmp);
for (int i = 0; i < n; i++) {
fa[i] = i; d[i] = 1;
}
int ind = 1;
int cur = n * (n - 1);
for (int i = 1; i <= q; i++) {
while (ind <= m && e[ind].w < a[i].first) {
int x = get(e[ind].u), y = get(e[ind].v);
if (x != y) {
fa[x] = y;
cur -= d[x] * d[y] * 2;
d[y] += d[x];
}
ind++;
}
b[a[i].second] = cur;
}
for (int i = 1; i <= q; i++) printf("%d\n", b[i]);
}
return 0;
}