[并查集][排序] Jzoj P4223 旅游
题解
- 题目大意:有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 }