很容易想到离线处理:将边按权值从小到大排序,将询问从小到大排序,然后对于某个询问,边权值不超过该次询问的边都加上,用并查集来维护答案。
1 #include <algorithm> 2 #include <iostream> 3 #include <cstring> 4 #include <cstdio> 5 using namespace std; 6 7 const int N = 20001; 8 const int M = 100000; 9 const int Q = 5000; 10 int f[N]; 11 int r[N]; 12 int ans[Q]; 13 int n, m, q; 14 15 void init() 16 { 17 for ( int i = 1; i <= n; i++ ) 18 { 19 f[i] = i; 20 r[i] = 1; 21 } 22 } 23 24 int findf( int x ) 25 { 26 if ( f[x] != x ) f[x] = findf( f[x] ); 27 return f[x]; 28 } 29 30 struct Edge 31 { 32 int u, v, w; 33 bool operator < ( const Edge & o ) const 34 { 35 return w < o.w; 36 } 37 } edge[M]; 38 39 struct Query 40 { 41 int id, val; 42 bool operator < ( const Query & o ) const 43 { 44 return val < o.val; 45 } 46 } query[Q]; 47 48 int main () 49 { 50 int t; 51 scanf("%d", &t); 52 while ( t-- ) 53 { 54 scanf("%d%d%d", &n, &m, &q); 55 init(); 56 for ( int i = 0; i < m; i++ ) 57 { 58 scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w); 59 } 60 sort( edge, edge + m ); 61 for ( int i = 0; i < q; i++ ) 62 { 63 query[i].id = i; 64 scanf("%d", &query[i].val); 65 } 66 sort( query, query + q ); 67 int cur = 0, cnt = 0; 68 for ( int i = 0; i < q; i++ ) 69 { 70 while ( cur < m && edge[cur].w <= query[i].val ) 71 { 72 int u = findf( edge[cur].u ), v = findf( edge[cur].v ); 73 if ( u != v ) 74 { 75 cnt += r[u] * r[v]; 76 f[u] = v; 77 r[v] += r[u]; 78 } 79 cur++; 80 } 81 ans[query[i].id] = cnt << 1; 82 } 83 for ( int i = 0; i < q; i++ ) 84 { 85 printf("%d ", ans[i]); 86 } 87 } 88 return 0; 89 }