[并查集][排序] Jzoj P4223 旅游

Description

 

Input

Output

 

Sample Input

1
5 5 3
2 3 6334
1 5 15724
3 5 5705
4 3 12382
1 3 21726
6000
10000
13000

Sample Output

2
6
12
 

Data Constraint

 

题解

  • 题目大意:有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 }

 

posted @ 2019-01-26 15:40  BEYang_Z  阅读(198)  评论(0编辑  收藏  举报