标签:
Time Limit: 1500/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1313 Accepted Submission(s): 472
题目大意:无向图。给你m条边,u - v 每条边有一个权值w。表示从城市u - v、v - u 的时间是w。然后q次询问。每次询问一个x值。表示问你当时间容忍为x时,可以走多少个城市对。每次到一个城市后可以休息,时间容忍会重新变为x。
解题思路:首先按边权把边排序。用并查集统计加入第k条边时可以走的城市对个数,记录在pair_cnt数组中。同时需要维护每个集合中的点的个数。最后在排完序后的边中二分找到第一个大于x的边的编号ck。然后在pair_cnt数组中找到编号ck-1即为答案。
#include<bits/stdc++.h> using namespace std; const int maxn=(1e4)*3; const int maxm=1e5+200; const int INF=0x3f3f3f3f; struct Edge{ int u,v,w; Edge(){} Edge(int _u,int _v,int _w){ u=_u; v=_v; w=_w; } }edges[maxm]; int cnt[maxn],pair_cnt[maxm]; int fa[maxn]; void init(int n){ for(int i=0;i<=n;i++){ fa[i]=i; cnt[i]=1; } } int Find(int x){ if(fa[x]!=x){ return fa[x]=Find(fa[x]); } return x; } int Union(int u,int v){ int fu=Find(u); int fv=Find(v); int ret; if(fu<fv){ ret=cnt[fu]*cnt[fv]*2; fa[fv]=fu; cnt[fu]+=cnt[fv]; return ret; }else if(fu>fv){ ret=cnt[fu]*cnt[fv]*2; fa[fu]=fv; cnt[fv]+=cnt[fu]; return ret; }else{ return 0; } } bool cmp(Edge a,Edge b){ return a.w<b.w; } int BinSearch(int l,int r,int key){ while(l<r){ int md=(l+r)/2; if(key<edges[md].w){ r=md; }else if(key>edges[md].w){ l=md+1; }else{ return md+1; } } return r; } int main(){ int t,n,m,q; scanf("%d",&t); while(t--){ scanf("%d%d%d",&n,&m,&q); init(n); for(int i=1;i<=m;i++){ scanf("%d%d%d",&edges[i].u,&edges[i].v,&edges[i].w); } sort(edges+1,edges+1+m,cmp); edges[0].w=-1;edges[m+1].w=INF; for(int i=1;i<=m;i++){ pair_cnt[i]=pair_cnt[i-1]+Union(edges[i].u,edges[i].v); } int tmp; for(int i=0;i<q;i++){ scanf("%d",&tmp); printf("%d\n",pair_cnt[BinSearch(0,m+1,tmp)-1]); } } return 0; }
HDU 5441——Travel——————【并查集+二分查界限】
标签:
原文地址:http://www.cnblogs.com/chengsheng/p/4812656.html