/*
本题题意有必要说一下, 给出一系列查询长度, 要求你找出任意两点间的最长边(a,b之间许多边中最长的边小于等于查询的能量值,这两点就满足条件)小于等于给出的查询
长度, 做法是对给出的边排序,具体看代码, 我也是看了别人写的才明白题意的。
做法: 我们把所有的边和所有查询排序(从小到大)如果当前边长小于等于查询长度。即合并此边(并查集)注意:
当要合并的两点是树时, 总的条数ans = suma*asumb;这样问题就解决了;
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int M = 10010;
struct node {
int x,y;
int d;
}edge[M*6];
struct Node {
int len;
int id;
int ans;
}query[M];
int sum[M], p[M];
int n, m, q;
bool cmp(node p1, node p2){
return p1.d < p2.d;
}
bool cmp1(Node p1, Node p2){
return p1.len < p2.len;
}
bool cmp2(Node p1, Node p2){
return p1.id < p2.id;
}
int Find(int x){
return x == p[x] ? x : p[x] = Find(p[x]);
}
int Union(int x, int y){
x = Find(x);
y = Find(y);
int temp = 0;
if(x != y){
p[x] = y;
temp = sum[x]*sum[y];
sum[y] += sum[x];
}
return temp;
}
void init(){
for(int i = 0; i < M; i++){
p[i] = i;
sum[i] = 1;
}
memset(edge, 0, sizeof(edge));
memset(query, 0, sizeof(query));
}
int main()
{
int a, b, d;
while(scanf("%d%d%d", &n, &m, &q) != EOF){
init();
for(int i = 0; i < m; i++){
scanf("%d%d%d", &a, &b, &d);
edge[i].x = a;
edge[i].y = b;
edge[i].d = d;
}
for(int i = 0; i < q; i++){
scanf("%d", &a);
query[i].id = i;
query[i].len = a;
query[i].ans = 0;
}
sort(edge, edge + m, cmp);
sort(query, query + q, cmp1);
int cnt = 0;
for(int i = 0; i < q; i++){
while(edge[cnt].d <= query[i].len && cnt < m){
query[i].ans +=Union(edge[cnt].x, edge[cnt].y);
cnt++;
}
if(i > 0)
query[i].ans += query[i-1].ans;
// printf("%d, %d\n", i,query[i].ans);
}
sort(query, query+ q, cmp2);
for(int i = 0; i < q; i++){
printf("%d\n", query[i].ans);
}
}
return 0;
}