题解
- 题目大意:有n个点,m条边,每条边有一个权值,每次问有多少个点对在不经过权值超过x的边可以到达
- 这题的话,可以将询问离线来做,将边权和询问权值从小到大排序
- 然后将边从小到大打进并查集里,当前边的贡献就是边所连的两点之间的子树大小的乘积*2的和
代码
1 #include <cstdio>
2 #include <iostream>
3 #include <cstring>
4 #include <algorithm>
5 #define N 200010
6 #define ll long long
7 using namespace std;
8 ll T,n,m,q,sum,l,fa[N],size[N],ans[N];
9 struct edge { ll x,y,d; }e[N],Q[N];
10 bool cmp(edge x,edge y) { return x.d<y.d; }
11 bool cmp1(edge x,edge y) { return x.x<y.x; }
12 ll getfather(ll x) {return !fa[x]?x:fa[x]=getfather(fa[x]);}
13 int main()
14 {
15 scanf("%lld",&T);
16 while (T--)
17 {
18 scanf("%lld%lld%lld",&n,&m,&q),l=1,sum=0,memset(ans,0,sizeof(ans)),memset(fa,0,sizeof(fa));
19 for (ll i=1;i<=n;i++) size[i]=1;
20 for (ll i=1;i<=m;i++) scanf("%lld%lld%lld",&e[i].x,&e[i].y,&e[i].d);
21 for (ll i=1;i<=q;i++) scanf("%lld",&Q[i].x),Q[i].d=i;
22 sort(e+1,e+m+1,cmp),sort(Q+1,Q+q+1,cmp1);
23 for (ll i=1;i<=q;i++)
24 {
25 while (l<m&&e[l].d<=Q[i].x)
26 {
27 ll u=getfather(e[l].x),v=getfather(e[l].y);
28 if (u!=v) fa[v]=u,sum+=size[u]*size[v]*2,size[u]+=size[v],size[v]=0;
29 l++;
30 }
31 ans[Q[i].d]=sum;
32 }
33 for (ll i=1;i<=q;i++) printf("%lld\n",ans[i]);
34 }
35 }