您的位置:首页 > 理论基础 > 计算机网络

hdu 4750 Count The Pairs(2013南京网络赛C题,并查集)

2013-10-29 00:05 393 查看
题意:有 n个点,m条边,现在定义f为任意两点间的每条路径上的最大边的最小值,给你一个t,问你f>=t的点对有多少个。

思路:像kruskal加边那样,从小往大加边,用并查集来维护点集合。

说明:1、对于一条边来说,且他的两个端点a,b不在一个集合里,那么以它为最大边的点对数为sum[a]*sum[b]*2,其中sum[x]为以x 为代表元的集合元素个数。

2、对于询问二分查找即可。

3、因为有些点可能成环,导致有些边作为不了最大边,应当在枚举最大边中删去,及那些两端点已经在一个集合的边。

代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=10000+100;
const int maxm=500000+100;
int p[maxn];
int rank[maxn];
int size[maxn];
int ans[maxm];
int res[maxm];
int n,m;
struct node
{
int from;
int to;
int w;
};
node edge[maxm];
bool cmp(const node &a,const node &b)
{
return a.w<b.w;
}
void init()
{
for(int i=0;i<n;i++)
{
p[i]=i;
rank[i]=0;
size[i]=1;
}
}
int find(int x)
{
if(x!=p[x])
{
p[x]=find(p[x]);
}
return p[x];
}
void merge(int a,int b)//合并
{
a=find(a);
b=find(b);
if(a==b)
{
return ;
}
else
{
if(rank[a]>rank[b])
{
p[b]=a;
size[a]+=size[b];
}
else
{
if(rank[a]==rank[b])
{
rank[b]++;
}
p[a]=b;
size[b]+=size[a];
}
}
}
int main()
{
// freopen("in.txt","r",stdin);
while(~scanf("%d%d",&n,&m))
{
init();
int a,b,c;
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&c);
edge[i].from=a;
edge[i].to=b;
edge[i].w=c;
}
sort(edge,edge+m,cmp);//排序
int cnt=0;
for(int i=0;i<m;i++)
{
int u=edge[i].from;
int v=edge[i].to;
u=find(u);
v=find(v);
if(u!=v)
{
ans[cnt]=size[u]*size[v]*2;
res[cnt++]=edge[i].w;
merge(u,v);
}
}
for(int i=1;i<cnt;i++)
{
ans[i]+=ans[i-1];
}
int q;
scanf("%d",&q);
while(q--)//输出答案
{
int a;
scanf("%d",&a);
int pp=lower_bound(res,res+cnt,a)-res;
printf("%d\n",ans[cnt-1]-ans[pp-1]);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  并查集