以前的一道题目 想起来又做了一遍 当时真的是毫无头绪 看了博客还是半懂不懂
现在独立思考已经可以有比较清晰地思路 也可能是因为做过类似的题目吧
题目所说的两点间f值即是 两点间所有路径中最长边的最小值 用最小生成树解决
先将边升序排序 这样当前遍历到的每一条边都是最长的 这个性质非常好
假设当前遍历到的边的两个点之前是不连通的 这样在两点间路径中的最长边(f值)就确定是当前边了
如果此两点之前已经连通 即是说两点间路径中最长边已经有了 但由于当前遍历到的边是最长的 所以不会再更新此两点的f值 可以忽略 符合最小生成树的操作
#include <bits/stdc++.h>
using namespace std;
struct node
{
int u;
int v;
int w;
};
node edge[500010];
int f[10010],num[10010],len[10010],pre[10010],presum[10010];
int n,m;
int cmp(node n1,node n2)
{
return n1.w<n2.w;
}
int getf(int p)
{
if(f[p]==p) return p;
else
{
f[p]=getf(f[p]);
return f[p];
}
}
int unite(int u,int v)
{
int fu,fv,sum;
fu=getf(u);
fv=getf(v);
if(fu!=fv)
{
f[fv]=fu;
sum=num[fu]*num[fv];
num[fu]+=num[fv];
num[fv]=0;
return sum;
}
else
{
return 0;
}
}
int main()
{
int i,j,cnt,u,v,w,t,q,p;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
}
sort(edge+1,edge+m+1,cmp);
for(i=0;i<n;i++)
{
f[i]=i;
num[i]=1;
}
memset(pre,0,sizeof(pre));
cnt=0;
for(i=1;i<=m;i++)
{
t=unite(edge[i].u,edge[i].v);
if(t!=0)
{
cnt++;
len[cnt]=edge[i].w;
pre[cnt]=t;
}
if(cnt==n-1) break;
}
memset(presum,0,sizeof(presum));
for(i=cnt;i>=1;i--)
{
presum[i]=presum[i+1]+pre[i];
}
scanf("%d",&q);
while(q--)
{
scanf("%d",&p);
p=lower_bound(len+1,len+cnt+1,p)-len;
printf("%d\n",presum[p]*2);
}
}
return 0;
}