hdu5441 并查集+克鲁斯卡尔算法

这题计算 一张图上 能走的 点对有多少个  对于每个限制边权 , 对每条边排序,对每个查询排序

然后边做克鲁斯卡尔算法 的时候变计算就好了

#include <iostream>
#include <algorithm>
#include <string.h>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
const int maxn=20005;
typedef long long LL;
struct edg{
   int a,b,d;
   edg(int ca=0,int cb=0,int cd=0)
   {
        a=ca; b=cb; d=cd;
   }
   bool operator <(const edg &rhs)const{
      return d<rhs.d;
   }
}E[100005];
struct query{
   LL id,d;
   query(LL cid=0, LL cd=0 ){
       id=cid; d=cd;
   }
   bool operator <(const query &rhs)const {
       return d<rhs.d;
   }
}Q[5005];
LL S[maxn];
LL num[maxn];
int fa[maxn];
int fin(int a)
{
     return fa[a]=(fa[a]==a)?a:fin(fa[a]);
}
LL ans[5005];
int main()
{

    int cas;
    scanf("%d",&cas);
    for(int cc=1; cc<=cas; cc++)
        {
             int n,m,q;
             scanf("%d%d%d",&n,&m,&q);
             for(int i=0; i<m; i++)scanf("%d%d%d",&E[i].a,&E[i].b,&E[i].d);
             for(int i=0; i<=n; i++){fa[i]=i;S[i]=0;num[i]=1;}
             for(int i=0; i<q; i++) {scanf("%I64d",&Q[i].d);Q[i].id=i; ans[i]=0;}
             sort(E,E+m);
             sort(Q,Q+q);
             int loc=0;
             LL D=0;
             for(int i=0; i<q; i++)
                {
                    while(loc<m&&E[loc].d<=Q[i].d){
                        int a=E[loc].a,b=E[loc].b;
                        a=fin(a);
                        b=fin(b);
                        if(a==b){ loc++; continue; }
                        D=D-S[a]-S[b];
                        fa[b]=a;
                        num[a]+=num[b];
                        S[a]=1LL*num[a]*(num[a]-1);
                        D=D+S[a];
                        loc++;
                    }
                   ans[Q[i].id]=D;
                }
                for(int i=0; i<q; i++)
                    printf("%I64d\n",ans[i]);
        }
    return 0;
}
时间: 2024-10-24 21:29:00

hdu5441 并查集+克鲁斯卡尔算法的相关文章

hdu 1233(还是畅通工程)(prime算法,克鲁斯卡尔算法)(并查集,最小生成树)

还是畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 26860    Accepted Submission(s): 11985 Problem Description 某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离.省政府"畅通工程"的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路

hdu 1233(还是畅通project)(prime算法,克鲁斯卡尔算法)(并查集,最小生成树)

还是畅通project Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 26860    Accepted Submission(s): 11985 Problem Description 某省调查乡村交通状况,得到的统计表中列出了随意两村庄间的距离.省政府"畅通project"的目标是使全省不论什么两个村庄间都能够实现公路交

hdu-1863畅通工程 最小生成树克鲁斯卡尔算法kruskal(并查集实现)

畅通工程 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 16994    Accepted Submission(s): 7134 Problem Description 省政府"畅通工程"的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可).经过调查评估,得到的统计表中列出

用并查集实现 kruskal算法

/**并查集实现克鲁斯卡尔算法61 2 62 4 11 4 21 3 13 5 44 5 3**/#include<iostream>#include<vector>#include<algorithm>#define MAX_N 100using namespace std; struct Node{ int numr; int numd; int val;}; int cmp(Node a,Node b){ return a.val<b.val;}vector

贪心算法(Greedy Algorithm)之最小生成树 克鲁斯卡尔算法(Kruskal&amp;#39;s algorithm)

克鲁斯卡尔算法(Kruskal's algorithm)是两个经典的最小生成树算法的较为简单理解的一个.这里面充分体现了贪心算法的精髓.大致的流程能够用一个图来表示.这里的图的选择借用了Wikipedia上的那个.很清晰且直观. 首先第一步,我们有一张图,有若干点和边 例如以下图所看到的: 第一步我们要做的事情就是将全部的边的长度排序,用排序的结果作为我们选择边的根据.这里再次体现了贪心算法的思想.资源排序,对局部最优的资源进行选择. 排序完毕后,我们领先选择了边AD. 这样我们的图就变成了 第

克鲁斯卡尔算法

环境: Codeblocks 13.12 + GCC 4.7.1 参考资料:<大话数据结构>,<啊哈算法>,百度百科 基本思想:(1)构造一个只含n个顶点,边集为空的子图.若将图中各个顶点看成一棵树的根节点,则它是一个含有n棵树的森林.(2)从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图.也就是说,将这两个顶点分别所在的两棵树合成一棵树:反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之(3)依次类推,直至森

最小生成树( 克鲁斯卡尔算法)

/* Name: Copyright: Author: Date: 01-12-14 20:17 Description: 最小生成树( 克鲁斯卡尔算法) 关于并查集的算法,参见<一种简单而有趣的数据结构--并查集>http://blog.csdn.net/qiaoruozhuo/article/details/39674991 */ #include<stdio.h> #include<stdlib.h> #define MAXN 1000 //最大顶点数量 #def

最小生成树算法(克鲁斯卡尔算法和普里姆算法)

一般最小生成树算法分成两种算法: 一个是克鲁斯卡尔算法:这个算法的思想是利用贪心的思想,对每条边的权值先排个序,然后每次选取当前最小的边,判断一下这条边的点是否已经被选过了,也就是已经在树内了,一般是用并查集判断两个点是否已经联通了: 另一个算法是普里姆算法:这个算法长的贼像迪杰斯塔拉算法,首先选取一个点进入集合内,然后找这个点连接的点里面权值最小的点,然后每次在选取与集合内任意一点连接的点的边的权值最小的那个(这个操作可以在松弛那里修改一下,这也是和迪杰斯塔拉算法最大的不同,你每次选取一个点后

最小生成树--克鲁斯卡尔算法(Kruskal)

按照惯例,接下来是本篇目录: $1 什么是最小生成树? $2 什么是克鲁斯卡尔算法? $3 克鲁斯卡尔算法的例题 摘要:本片讲的是最小生成树中的玄学算法--克鲁斯卡尔算法,然后就没有然后了. $1 什么是最小生成树? •定义: 先引入一个定理:N个点用N-1条边连接成一个联通块,形成的图形只可能是树,没有别的可能: 根据这个定理,我们定义:在一个有N个点的图中,选出N-1条边出来,连接所有N个点,这N-1条边的边权之和最小的方案: •最小生成树之prim算法:   由于本蒟蒻还不会这个算法,所以