hdu-3938-Portal-并查集

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


简单的讲就是,给你一张无向图,求有多少对点之间的路径花费小于L

这里路径花费:u-v 两点之间的多条路径中的最长的边最小值,一条路径中最长的边为其花费,若有多条取最长边最短的一条边。


数据规模:

There are multiple test cases. The first line of input contains three integer N, M and Q (1 < N ≤ 10,000, 0 < M ≤ 50,000, 0 < Q ≤ 10,000). N is the number of points, M is the number of edges and Q is the number of queries. Each of the next M lines contains three integers a, b, and c (1 ≤ a, b ≤ N, 0 ≤ c ≤ 10^8) describing an edge connecting the point a and b with cost c. Each of the following Q lines contain a single integer L (0 ≤ L ≤ 10^8).

可以知道 对于长度为L的询问,可以利用前面的结果更新答案,所以离线处理询问。


对q个询问长度L升序排序,边权升序排序;

遍历L,对比L小的边,取出边对应的uv,看是否联通,如果联通跳过,否则便合并两个集合,而此时导致,与u联通的点集 与  【与v连通的点集】 联通了, 因此新增的点对数,为两者乘积,不断更新答案,o(m)复杂度

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;

const double pi=acos(-1.0);
double eps=0.000001;

int fa[11234];
int num[11234]; //记录该树下有多少儿子
int find(int x)
{
    if (fa[x]==x)
        return x;
    else return fa[x]=find(fa[x]);
}
struct node
{
    int x,y,z;
    node() {}
};

node tm[51234];
bool cmp1(node a,node b)
{
    return a.z<b.z;
}
struct que
{
    int id,x;
};
que qus[11234];
bool cmp2(que a,que b)
{
    return a.x<b.x;
}
long long ans[11234];
int main()
{
    int n,m,q;
    while(scanf("%d%d%d",&n,&m,&q)!=EOF)
    {
        int x,y,z;
        for (int i=1; i<=m; i++)
        {
            scanf("%d %d %d",&x,&y,&z);
            tm[i].x=x;
            tm[i].y=y;
            tm[i].z=z;
        }
        sort(tm+1,tm+1+m,cmp1);
        for (int i=1; i<=q; i++)
        {
            scanf("%d",&qus[i].x);
            qus[i].id=i;
        }
        sort(qus+1,qus+1+q,cmp2);
        for (int i=1; i<=n; i++) fa[i]=i,num[i]=1;
        long long sum=0;
         int j=1;
        for (int i=1; i<=q; i++)
        {

            for (; j<=m; j++)
            {
                if (tm[j].z>qus[i].x) break;
                int x=tm[j].x;
                int y=tm[j].y;
                int fx=find(x);
                int fy=find(y);
                if (fx!=fy)
                {
                    fa[fx]=fy;
                    sum+=num[fx]*num[fy];
                    num[fy]+=num[fx];
                }
            }
            ans[qus[i].id]=sum;
        }
        for (int i=1; i<=q; i++)
        {
            printf("%lld\n",ans[i]);
        }
    }


    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值