P2573 [SCOI2012] 滑雪 —— 生成树

[SCOI2012] 滑雪

题目描述

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

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

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

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

输入格式

输入的第一行是两个整数 n,m
接下来一行有 n 个整数 hi,分别表示每个景点的高度。

接下来 m 行,表示各个景点之间轨道分布的情况。每行三个整数 u,v,k,表示编号为 u 的景点和编号为 v 的景点之间有一条长度为 k 的轨道。

输出格式

输出一行,表示 a180285 最多能到达多少个景点,以及此时最短的滑行距离总和。

样例 #1

样例输入 #1

3 3
3 2 1
1 2 1
2 3 1
1 3 10

样例输出 #1

3 2

提示

【数据范围】
对于 30 的数据,1n2000
对于 100 的数据,1n105

对于所有的数据,保证 1m106 , 1hi1091ki109

分析

先从1号点出发搜索所有能遍历的点,顺便记下遍历过的边。

以终点的高度为第一关键字从大到小,以边的长度为第二关键字从小到大,对标记的边排序。

前者保证能遍历尽可能多的点,后者保证最小距离。

合并边到新的生成树上即可。

注意同样高度的点建双向边。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+100,M=1e6+100;
struct edge{int y,n,x;long long z;}e[M<<1],t[M<<1];
int n,m,h[N],f[N];
int tot,cnt,head[N],sum;
int dh[N],rec[N],q[M];
bool vis[N];
long long dis;
bool cmp(edge a,edge b)
{
if(h[a.y]==h[b.y])return a.z<b.z;
return h[a.y]>h[b.y];
}
int fin(int x)
{
if(f[x]==x)return x;
f[x]=fin(f[x]);
return f[x];
}
void bfs()
{
int he=1,ta=0;
q[++ta]=1;sum=1;vis[1]=1;
while(he<=ta)
{
int u=q[he];
++he;
for(int i=head[u];i;i=e[i].n)
{
int v=e[i].y;
t[++cnt].n=dh[u];
t[cnt].y=v;
t[cnt].z=e[i].z;
t[cnt].x=u;
dh[u]=cnt;
if(!vis[v])
{
vis[v]=1;
++sum;
q[++ta]=v;
}
}
}
}
void go(int u,int fa,long long len)
{
bool fl=0;
for(int i=dh[u];i;i=t[i].n)
{
int v=t[i].y;
if(v==fa)continue;
go(v,u,len+t[i].z);
fl=1;
}
if(!fl)dis+=len;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i){f[i]=i;scanf("%d",h+i);}
for(int i=1,x,y;i<=m;++i)
{
long long z=0;
scanf("%d%d%lld",&x,&y,&z);
if(h[x]<h[y])swap(x,y);// x --> y
e[++tot].n=head[x];
e[tot].x=x;
e[tot].y=y;
e[tot].z=z;
head[x]=tot;
if(h[x]==h[y])
{
e[++tot].n=head[y];
e[tot].x=y;
e[tot].y=x;
e[tot].z=z;
head[y]=tot;
}
}
bfs();
sort(t+1,t+1+cnt,cmp);
int num=0;
for(int i=1,x,y,fx,fy;i<=cnt;++i)
{
x=t[i].x;
y=t[i].y;
fx=fin(x);
fy=fin(y);
if(fx!=fy)
{
f[fy]=fx;
dis+=t[i].z;
++num;
if(num==sum-1)break;
}
}
printf("%d %lld",sum,dis);
return 0;
}
posted @   Glowingfire  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示