北京师范大学校赛 F. 汤圆防漏理论(贪心&&set)

题目链接

http://www.bnuoj.com/v3/contest_show.php?cid=9358#problem/F

题目

Time Limit: 1000msMemory Limit: 262144KB 64-bit integer IO format: %lld Java class name: Main
Submit Status PID: 53076
ghc很喜欢吃汤圆,但是汤圆很容易被粘(zhān)漏。

根据多年吃汤圆经验,ghc总结出了一套汤圆防漏理论:

互相接触的汤圆容易粘(zhān)在一起,并且接触面积不同,粘(zhān)在一起的粘(nián)度也不同。

当ghc要夹起一个汤圆时,这个汤圆和现在碗里与这个汤圆接触的所有汤圆之间的粘(nián)度的和,如果大于汤圆的硬度,这个汤圆就会被粘(zhān)漏。

今天ghc又要煮汤圆啦,今天要煮n个汤圆,并且摆盘的方法已经设计好:

汤圆按照1, 2, \dots , n编号,有m对汤圆互相接触,用x_i, y_i, z_i表示编号为x_i和y_i的两个汤圆互相接触,粘(nián)度为z_i。

汤圆当然是越软越好吃,但是ghc的厨艺只允许把所有汤圆煮成同样的硬度。那么,汤圆的硬度最小可以是多少,可以满足吃的过程中,存在一种夹汤圆的顺序,使得没有汤圆会被粘(zhān)漏呢?

注意:

不考虑汤圆的重力作用;

不能同时夹多个汤圆;

吃完汤圆一定要喝点汤。

Input

第一行是一个正整数T(\leq 5),表示测试数据的组数,

对于每组测试数据,

第一行是两个整数n,m(1\leq n,m\leq 100000),

接下来m行,每行包含三个整数x_i, y_i, z_i(1\leq x_i, y_i \leq n, x_i \neq y_i, 1 \leq z_i \leq 1000000),

同一对汤圆不会出现两次。

Output

对于每组测试数据,输出一行,包含一个整数,表示汤圆硬度的最小值。

Sample Input

1
4 6
1 2 2
1 3 2
1 4 2
2 3 3
2 4 3
3 4 5

Sample Output

6

分析

用一个有序集合set来维护汤圆,set里面存放一个二元组<粘度和,汤圆编号>。每次取出set的第一个元素,也就是粘度和最小的汤圆,然后修改与该汤圆所有相接触的汤圆的粘度和。set本身是不支持修改集合内元素的功能的,但是可以通过删除原有元素、插入修改后元素来实现。只需遍历一遍汤圆和所有边,所有时间复杂度为O( (n+m)logn).

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
typedef long long ll;
typedef pair<ll,ll> pa;
set<pa> s; //set自动排序,按第一个关键字
vector<pa> g[maxn];
ll nd[maxn]; //汤圆的粘度
ll vis[maxn];

void init()
{
    memset(nd,0,sizeof(nd));
    for(int i=0;i<maxn;i++) g[i].clear();
    s.clear();
    memset(vis,0,sizeof(vis));
}
int main()
{
    ll T;
    cin>>T;
    while(T--)
    {
        init();
        ll n,m;
        cin>>n>>m;
        for(int i=1;i<=m;i++)
        {
            int x,y,z;
            cin>>x>>y>>z;
            g[x].push_back(pa(y,z));
            g[y].push_back(pa(x,z));
            nd[x]+=z;
            nd[y]+=z;
        }
        //将所有汤圆放入集合
        for(int i=1;i<=n;i++) s.insert(make_pair(nd[i],i));

        //一个一个取汤圆
        ll ans=0;
        while(!s.empty())
        {
            set<pa>::iterator it;
            it=s.begin();
            pa now=*it;
            ans=max(ans,now.first);
            s.erase(it);
            //更新粘度
            ll u=now.second;
            vis[u]=1;
            for(ll i=0;i<g[u].size();i++)
            {
                ll v=g[u][i].first;
                if(vis[v]) continue;//只看父子边
                it=s.find(pa(nd[v],v));
                s.erase(it);
                nd[v]-=g[u][i].second;
                s.insert(pa(nd[v],v));
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值