鏈接:
題意:
T組樣例,每組樣例給定一個帶邊權的無向圖,有q個詢問,每次詢問給定x,只保留權值<=x的邊的話,輸出有所有奇數個點的連通塊中點對的數量和。
思路:
根據邊權大小對邊排序,從小到大逐漸加入圖中,遇到詢問時進行查詢。連通塊大小通過並查集維護。
代碼:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
static const int maxn = 100010;
static const int INF = 0x3f3f3f3f;
static const int mod = (int)1e9 + 7;
static const double eps = 1e-6;
static const double pi = acos(-1);
void redirect(){
#ifdef LOCAL
freopen("test.txt","r",stdin);
#endif
}
struct node{
int x,y,z;
}p[maxn];
bool operator < (const node& a,const node& b){
return a.z < b.z;
}
struct Query{
int id,val;
}q[5050];
bool operator < (const Query& a,const Query& b){
return a.val < b.val;
}
ll ans[5050];
int sz[maxn];
int fa[maxn];
inline int find(int x){
if(fa[x] == x)return x;
fa[x] = find(fa[x]);
return fa[x];
}
inline void combine(int x,int y,ll& sum){
int fx = find(x),fy = find(y);
if(fx != fy){
sum += (sz[fx]+sz[fy]) * (sz[fx]+sz[fy]-1) - sz[fx]*(sz[fx]-1) - sz[fy]*(sz[fy]-1);
sz[fx] += sz[fy];
fa[fy] = fx;
}
}
int main(){
redirect();
int T,n,m,qu;
scanf("%d",&T);
while(T--){
fill(sz,sz+maxn,1);
for(int i = 1;i < maxn;i++)fa[i] = i;
scanf("%d %d %d",&n,&m,&qu);
for(int i = 1;i <= m;i++)scanf("%d %d %d",&p[i].x,&p[i].y,&p[i].z);
sort(p+1,p+1+m);
for(int i = 1;i <= qu;i++){
q[i].id = i;
scanf("%d",&q[i].val);
}
sort(q+1,q+1+qu);
int j = 1;
ll sum = 0;
for(int i = 1;i <= qu;i++){
while(j <= m && p[j].z <= q[i].val)combine(p[j].x,p[j].y,sum),j++;
ans[q[i].id] = sum;
}
for(int i = 1;i <= qu;i++)printf("%lld\n",ans[i]);
}
return 0;
}