bzoj2753: [SCOI2012]滑雪与时间胶囊 MST

70 篇文章 0 订阅
44 篇文章 0 订阅

M的数据范围是[1,2000000],神坑1。

边两端高度相同时要建双向边,神坑2。

若边i的起点和终点未访问过,则表明边i是废边(与起点1不连通),神坑3。

那么对于添边,我们可以看做是现有一颗树,通过连接一条边将一个点加入到树里的过程

那么对于添加一个点,假设有一种方案先加入X,然后加入Y,HIGH[X]<HIGH[Y]那么肯定

可以找到另一种添加方式,先加入Y,再加入X,因为Y比X高,也就是既然能先加X,X肯定不

影响Y的合法性,也就是以高度为优先级,保证了合法性,神坑4

/**************************************************************
    Problem: 2753
    User: xujiahe
    Language: C++
    Result: Accepted
    Time:12208 ms
    Memory:69212 kb
****************************************************************/
 
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define ll long long
#define maxn 2100000
int hight[maxn],p[maxn],father[maxn];
int n,m,num;
bool vis[maxn];
struct node
{
    long long val;
    int v,u,next;
}edge[maxn];
void build(int x,int y,long long z)
{
    num++;
    edge[num].v=x;
    edge[num].u=y;
    edge[num].val=z;
    edge[num].next=p[x];
    p[x]=num;
}
void bfs()
{
    int ans1=0;
    vis[1]=1;
    queue<int>q;
    q.push(1);
    while(!q.empty())
    {
        int v=q.front();
        q.pop();
        ans1++;
        for(int e=p[v];e;e=edge[e].next)
        {
            if(!vis[edge[e].u])
            {
                vis[edge[e].u]=1;
                q.push(edge[e].u);
            }
        }
    }
    printf("%d ",ans1);
}
bool cmp(node aa,node bb)
{
    return hight[aa.u]>hight[bb.u]||((hight[aa.u]==hight[bb.u])&&(aa.val<bb.val));
}
int getfather(int x)
{
    if(x==father[x])
        return x;
    return father[x]=getfather(father[x]);
}
void kru()
{
    long long ans2=0;
    sort(edge+1,edge+num+1,cmp);
    for(int i=1;i<=num;i++)
    {
        int r1=getfather(edge[i].v);
        int r2=getfather(edge[i].u);
        if(!vis[edge[i].v]||!vis[edge[i].u]) continue;
        if(r1!=r2)
        {
            father[r1]=r2;
            ans2+=edge[i].val;
        }
    }
    printf("%lld",ans2);
}
int main()
{
    int x,y;
    long long z;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        father[i]=i;
    for(int i=1;i<=n;i++)
        scanf("%d",&hight[i]);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%lld",&x,&y,&z);
        if(hight[x]>=hight[y]) build(x,y,z);
        if(hight[y]>=hight[x]) build(y,x,z);
    }
    bfs();
    kru();
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值