>Description
>Input
>Output
>Sample Input
1
5 5 3
2 3 6334
1 5 15724
3 5 5705
4 3 12382
1 3 21726
6000
10000
13000
>Sample Output
2
6
12
>解题思路
并查集实现。
把边和询问的x都排个序,如果边的人气值小于等于x的话就把边连接的两点(x,y)进行合并,同时顺便记录一下 s [ i ] s[i] s[i]每个集合的总数,ans累加上 s [ x ] ∗ s [ y ] ∗ 2 s[x]*s[y]*2 s[x]∗s[y]∗2
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define int long long
using namespace std;
struct line
{
int x, y, c;
} a[100005];
struct ask
{
int h, c, ans;
} w[5005];
int T, n, m, q, c[20005], s[20005];
int read ()
{
int l = 0;
char cc = getchar();
while (cc > '9' || cc < '0') cc = getchar();
while (cc >= '0' && cc <= '9')
{
l = l * 10 + cc - '0';
cc = getchar();
}
return l;
}
bool bmp (line aa, line bb) {return aa.c < bb.c;}
bool bmp2 (ask aa, ask bb) {return aa.c < bb.c;}
bool bmp3 (ask aa, ask bb) {return aa.h < bb.h;}
int find (int now)
{
if (c[now] == now) return now;
s[c[now]] += s[now];
s[now] = 0; //处理集合大小
return c[now] = find (c[now]);
}
void work ()
{
n = read (), m = read (), q = read ();
for (int i = 1; i <= n; i++)
c[i] = i, s[i] = 1; //清空
for (int i = 1; i <= m; i++)
a[i].x = read (), a[i].y = read (), a[i].c = read ();
sort (a + 1, a + 1 + m, bmp); //边排个序
for (int i = 1; i <= q; i++)
w[i].c = read (), w[i].h = i;
sort (w + 1, w + 1 + q, bmp2); //询问排个序
int p = 1;
w[0].ans = 0;
for (int k = 1; k <= q; k++)
{
w[k].ans = w[k - 1].ans;
for (int i = p; i <= m; i++) //p记录上一次询问到的边
{
if (a[i].c > w[k].c) {p = i; break;}
int u = find (a[i].x), v = find (a[i].y);
if (u != v)
{
c[u] = v;
w[k].ans += s[v] * s[u] * 2;
s[v] += s[u], s[u] = 0;
}
}
}
sort (w + 1, w + 1 + q, bmp3); //按输入顺序输出
for (int i = 1; i <= q; i++)
printf ("%lld\n", w[i].ans);
}
signed main()
{
T = read ();
for (int i = 1; i <= T; i++)
work ();
return 0;
}