把查询离线会让复杂度变得非常优秀,因为每一条边只被查询一次。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e4+50,maxm=1e5+40;
int fa[maxn];
long long cnt[maxn];
int n,m,test,q,x;
long long tot;
struct mint
{
int u,v,w;
}e[maxm];
bool cmp(mint a,mint b)
{
return a.w < b.w;
}
struct anss
{
int id,size;
long long sum;
}ans[maxn];
bool cmpanssize(anss a,anss b)
{
return a.size < b.size;
}
bool cmpansid(anss a,anss b)
{
return a.id < b.id;
}
int Find(int x)
{
if(fa[x]==x) return x;
cnt[fa[x]]+=cnt[x];
cnt[x]=0;
return fa[x]=Find(fa[x]);
}
void Merge(int x,int y)
{
int xx=Find(x),yy=Find(y);
tot+=cnt[xx]*cnt[yy]*2;
fa[xx]=yy;
cnt[yy]+=cnt[xx];
cnt[xx]=0;
}
int main()
{
scanf("%d",&test);
for(int h=1;h<=test;++h)
{
tot=0;
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;++i) cnt[i]=1;
for(int i=1;i<=m;++i) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
sort(e+1,e+m+1,cmp);
for(int g=1;g<=q;++g)
{
scanf("%d",&ans[g].size);
ans[g].id=g;
ans[g].sum=0;
}
sort(ans+1,ans+q+1,cmpanssize);
// for(int i=1;i<=q;++q) printf("size=%d sum=%lld id=%d\n",ans[i].size,ans[i].sum,ans[i].id);
int place=1;
for(int i=1;i<=n;++i) fa[i]=i;
for(int i=1;i<=q;++i)
{
for(int j=place;j<=m;++j)
{
if(ans[i].size < e[j].w)
{
place=j;
break;
}
else if(Find(e[j].u) != Find(e[j].v)) Merge(Find(e[j].u),Find(e[j].v));
}
ans[i].sum=tot;
}
sort(ans+1,ans+q+1,cmpansid);
for(int i=1;i<=q;++i) printf("%lld\n",ans[i].sum);
}
return 0;
}