HDU5441 Travel 并查集

http://acm.hdu.edu.cn/showproblem.php?pid=5441


无向图,n个点,m条带权边,q次询问,给出数值d,点a可以到点b当且仅当存在一条路线其中最大的权值不超过d。


用sum记录连通块节点个数,两个连通块合并,结果增加( sum[a] + sum[b] ) * ( sum[a] + sum[b] - 1 ) - sum[a] * ( sum[a] - 1 ) - sum[b] * ( sum[b] -1 )


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=1e5+5;
struct node
{
    int a;
    int b;
    int c;
};
int father[N];
node p[N];
int num[N];
ll sum[N];//表示该点所在连通块的节点个数
int r[N];
ll ans[N];
int finds(int x)
{
    if(father[x]!=x)
    father[x]=finds(father[x]);
    return father[x];
}
bool cmp(node x,node y)
{
    return x.c<y.c;
}
void connect(int a,int b)
{
    if(r[a]>r[b])
    father[b]=a;
    else if(r[a]<r[b])
    father[a]=b;
    else
    {
        father[a]=b;
        r[b]++;
    }
    sum[a]=sum[b]=sum[a]+sum[b];
}
int main()
{
    int T,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        int n,m,q;
        scanf("%d%d%d",&n,&m,&q);
        for(int i=1;i<=m;i++)
        {
            sum[i]=1;
            father[i]=i;
            scanf("%d%d%d",&p[i].a,&p[i].b,&p[i].c);
        }
        sort(p+1,p+m+1,cmp);//首先按权值进行排序
        for(int i=1;i<=m;i++)
        {
            int a=finds(p[i].a);
            int b=finds(p[i].b);
            if(a!=b)
            {
                ans[i]=ans[i-1]+(sum[a]+sum[b])*(sum[a]+sum[b]-1)-sum[a]*(sum[a]-1)-sum[b]*(sum[b]-1);//连通块合并结果增加
                connect(a,b);
            }
            else
            ans[i]=ans[i-1];
            num[i]=p[i].c;
        }
        while(q--)
        {
            int x;
            scanf("%d",&x);
            int t=upper_bound(num+1,num+m+1,x)-num-1;
            printf("%lld
",ans[t]);
        }
    }
    return 0;
}

 


原文地址:https://www.cnblogs.com/westwind1005/p/5975219.html