BUPT Summer Journey #test9 B

 

B. 小妹妹送很多快递 2014新生暑假个人排位赛09

时间限制 1000 ms     内存限制 65536 KB    

题目描述

Mays王国的女王大人每天过着自由自在的生活,她最大的乐趣就是给邻国的帅气王子写信。但是最近,Mays王国的叔叔们变得很无聊,他们知道女王大人每次都把信委托给皇家小妹妹快递公司的小妹妹们,于是叔叔们给每一条路都设立了路障,只有小妹妹们给他们表演节目才会让小妹妹们过去。
在每一个路障,都有不同数量的叔叔,只有表演的小妹妹的数量不少与叔叔的数量的时候叔叔才会放她们过去。
可是七夕快要到了,Masy王国的每一个人都在给自己的情人写信。
Mays王国由n个地区组成,一些双向的道路连接着这些地区。注意两个地区之间可能有多条道路相通。
无聊的单身的beegerous已经算出了从一点到另一点送信最少需要的小妹妹的数量,为了表达对世界的不满,他脑补出了小妹妹们给任意两个点之间送信的画面,这样她们一共需要送n*(n-1)次信!如果所有的信件必须同一时间发出,这样每一次快递都需要由不同的小妹妹们来送!这样就会有好多好多小妹妹在Mays王国的道路上忙碌了。
请问,按上述脑补情形,皇家小妹妹快递公司一共需要派出多少小妹妹。

输入格式

输入第一行为数据组数T(T<=10),接下来T组数据,每组第一行为n,m,,2<=n<=10000,1<=m<=100000,表示Mays王国的道路由n个节点组成,接下来m行,每行一组u,v,c表示连接节点u,v的一条无向道路,且路障上有c个叔叔,1<=u,v<=n,0<=c<=100。
输入保证任意两点之间可达。

输出格式

每组数据输出一个数字,表示小妹妹快递公司最少需要派出的小妹妹数量。

输入样例

1
3 3
1 2 1
2 3 1
1 3 3

输出样例

6

hint:
9种送快递的方式及花费为:
1 --> 2:  1
1 --> 3:  1
2 --> 1:  1
2 --> 3:  1
3 --> 1:  1
3 --> 2:  1
答案为6

 

思路:由于这一次要求每一个的最少的小妹妹数。由于小妹妹数是不会消耗的。我们可以从边开始拓展。先排序。然后从小到大加入边后并查集,所需的小妹妹即两个集合的小妹妹的个数相乘乘以新加进来的v再乘以2(由于需要互相送)。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
//#define LOCAL
using namespace std;
struct Edge
{
    int from,to,v,next;
    bool operator < (const Edge &a) const
    {
        return v<a.v;
    }
}e[200005];
int father[20005],sum[20005],cnt;
int n,m;
int h[20005];
long long ans;
void AddEdge(int x,int y,int v)
{
    cnt++;e[cnt].from=x;e[cnt].to=y;e[cnt].v=v;e[cnt].next=h[x];h[x]=cnt;
}
int getfather(int x)
{
    if(x==father[x])return x;
    father[x]=getfather(father[x]);
    return father[x];
}
void Union(int x,int y,int v)
{
    int fx=getfather(x),fy=getfather(y);
    if(fx!=fy)
    {
        father[fy]=fx;
        ans=ans+((long long)sum[fx]*(long long)v*(long long)2*(long long)sum[fy]);
        sum[fx]=sum[fx]+sum[fy];
    }
}
int main()
{
    #ifdef LOCAL
    freopen("input.txt","r",stdin);
    #endif // LOCAL
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        cnt=0;
        memset(h,-1,sizeof(h));
        int x,y,v;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&x,&y,&v);
            if(v==0)v=1;
            AddEdge(x,y,v);
            AddEdge(y,x,v);
        }
        sort(e+1,e+1+cnt);
        for(int i=1;i<=n;i++)father[i]=i;
        for(int i=1;i<=n;i++)sum[i]=1;
        ans=0;
        for(int i=1;i<=cnt;i++)
        {
            x=e[i].from;y=e[i].to;v=e[i].v;
            Union(x,y,v);
        }
        printf("%lld\n",ans);
    }
    return 0;
}


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值