点击打开链接
以前的一道题目 想起来又做了一遍 当时真的是毫无头绪 看了博客还是半懂不懂
现在独立思考已经可以有比较清晰地思路 也可能是因为做过类似的题目吧
题目所说的两点间f值即是 两点间所有路径中最长边的最小值 用最小生成树解决
先将边升序排序 这样当前遍历到的每一条边都是最长的 这个性质非常好
假设当前遍历到的边的两个点之前是不连通的 这样在两点间路径中的最长边(f值)就确定是当前边了
如果此两点之前已经连通 即是说两点间路径中最长边已经有了 但由于当前遍历到的边是最长的 所以不会再更新此两点的f值 可以忽略 符合最小生成树的操作
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;
}
                










