P2573 [SCOI2012] 滑雪

P2573 [SCOI2012] 滑雪

题目描述

a180285 非常喜欢滑雪。他来到一座雪山,这里分布着 \(m\) 条供滑行的轨道和 \(n\) 个轨道之间的交点(同时也是景点),而且每个景点都有一编号 \(i\space (1 \le i \le n)\) 和一高度 \(h_i\)

a180285 能从景点 \(i\) 滑到景点 \(j\) 当且仅当存在一条 \(i\)\(j\) 之间的边,且 \(i\) 的高度不小于 \(j\)。与其他滑雪爱好者不同,a180285 喜欢用最短的滑行路径去访问尽量多的景点。如果仅仅访问一条路径上的景点,他会觉得数量太少。

于是 a18028 5拿出了他随身携带的时间胶囊。这是一种很神奇的药物,吃下之后可以立即回到上个经过的景点(不用移动也不被认为是 a180285 滑行的距离)。

请注意,这种神奇的药物是可以连续食用的,即能够回到较长时间之前到过的景点(比如上上个经过的景点和上上上个经过的景点)。 现在,a180285站在 \(1\) 号景点望着山下的目标,心潮澎湃。他十分想知道在不考虑时间胶囊消耗的情况下,以最短滑行距离滑到尽量多的景点的方案(即满足经过景点数最大的前提下使得滑行总距离最小)。你能帮他求出最短距离和景点数吗?

说明/提示

对于所有的数据,保证 $ 1 \le m \le 10^6 $ , $ 1 \le h_i \le 10^9 $ ,$ 1 \le k_i \le 10^9 $。

Solution:

感觉是我做过的第一道类似于重构树的题目 虽然不是

首先我们不难想到将可行的路径先建出来,由高的点向低的点连边,高度相同连双向边。

那么我们在这个图上先以 1 为起点染个色,标记一下哪一些点是可以到达的,然后再将到达他们的边存起来。然后我们希望在这个图上分层以找出最小生成树,但是由于我们的很多边并非双向边,所以我们在建最小生成树时应该按照起点的高度为第一关键字,边权为第二关键字来排序。

Code:

#include <bits/stdc++.h>
using namespace std;
int n,m,cnt,tot,p;
const int N=1e5+5;
const int M=1e6+5;
long long ans;
int h[N],head[N],dis[N],vis[N],f[N];
struct Edge{
    int to,v,ne;
}edge[M<<1];
struct Rode{
    int v,u,to;
}r[M<<1];
void add(int x,int y,int v)
{
    edge[++cnt].to=y;edge[cnt].v=v,edge[cnt].ne=head[x];head[x]=cnt;
}
void dfs(int x)
{
    for(int i=head[x];~i;i=edge[i].ne)
    {
        int v=edge[i].to;
        if(!dis[v])
        {
            dis[v]=1;
            p++;
            dfs(v);
        }
    }
}
void init()
{
    for(int i=1;i<=n;i++)
    {
       head[i]=-1;
       f[i]=i;
    }
}
bool cmp(Rode r1,Rode r2)
{
    if(h[r1.to]==h[r2.to])
    return r1.v<r2.v;
    return h[r1.to]>h[r2.to];
}
int find(int x)
{
    if(f[x]==x)return x;
    f[x]=find(f[x]);
    return f[x];
}
int main()
{
    //freopen("capsule.in","r",stdin);
   // freopen("capsule.out","w",stdout);
    cin>>n>>m;
    init();
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&h[i]);
    }
    for(int i=1,x,y,v;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&v);
        if(h[y]==h[x])
        {
            add(x,y,v);
            add(y,x,v);
            continue;
        }
        if(h[y]>h[x])swap(x,y);
        add(x,y,v);
    }
    dis[1]=1;
    dfs(1);
    p++;
    for(int u=1;u<=n;u++)
    {
        if(dis[u])
        {
            for(int i=head[u];~i;i=edge[i].ne)
            {
                int v=edge[i].to;
                if(dis[v])
                {
                    r[++tot]=(Rode){edge[i].v,u,v};
                }
            }
        }
    }
    sort(r+1,r+1+tot,cmp);
    for(int i=1;i<=tot;i++)
    {
        int u=r[i].u,v=r[i].v,to=r[i].to;
        int fu=find(u),fto=find(to);
        if(fu!=fto)
        {
            f[fto]=fu;
            ans+=v;
        }
        //cout<<cnt1<<endl;
    }
    cout<<p<<" "<<ans;
    return 0;
}
posted @ 2025-04-10 13:05  liuboom  阅读(9)  评论(0)    收藏  举报