1 条题解

  • 0
    @ 2025-10-17 18:38:50

    题解

    滑雪只能沿着高度不升的轨道前进,因此我们先从 1 号景点出发做一次 BFS,仅保留满足 H[u] ≥ H[v] 的有向边,把所有能够到达的景点标记出来;这些点的数量就是可以游览的最大景点数。随后只在这个可达子图上考虑轨道,针对每条原始无向边按照高度关系至多保留一个方向(高→低),并按“终点高度从高到低、同高度下长度从小到大”的顺序排序。这样用 Kruskal 在这些有向边上生成一棵(或若干棵)最小生成树,就能保证在覆盖全部可达景点的前提下,滑行总距离最小。由于时间胶囊可以让滑雪者在树上随意回溯,树结构即可满足行程需要,输出的就是最多可达景点数以及对应的最短滑行距离和。

    // 只能从点权大的点到小的点,于是这么建边
    // 那么显然我们需要的是一个树形结构,这样每条边最多走一次
    // 那么搜索出所有能到达的点再Kruscal?
    // 在落点高度相同的情况下,我们优先选择边权最小的
    // 否则我们必须考虑更高的,以保证正确性
    //#define DEBUG
    
    #ifdef DEBUG
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<time.h>
    #include<string.h>
    #include<memory.h>
    #include<random>
    #include<unordered_map>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    #include<deque>
    #include<algorithm>
    #endif
    
    #ifndef DEBUG
    #include<bits/stdc++.h>
    #endif
    
    using namespace std;
    
    bool MEMST;
    int clock_st = clock();
    #define ll long long
    #define ull unsigned long long
    #define pii pair<ll,ll>
    #define pb push_back
    #define fi first
    #define se second
    #define il inline
    #define reg register
    #define ld long double
    #define fastio ios::sync_with_stdio(false), cin.tie(0)
    #define LEFT (POS*2)
    #define RIGHT (POS*2+1)
    #define lc(x) tr[x].l ? tr[x].l : tr[x].l=++tlt
    #define rc(x) tr[x].r ? tr[x].r : tr[x].r=++tlt
    #define lll __int128
    mt19937_64 engine(time(0));
    const ll N = 1e5+5;
    const ll M = 2e6+5;
    vector<pii> E[N];
    ll n,m,H[N],tlt,fa[N];
    struct Edge{
    	ll u,v,w;
    	il bool operator <(const Edge &ano){
    		if(H[v] == H[ano.v]) return w < ano.w;
    		return H[v] > H[ano.v];
    	}
    } Edges[M], G[M];
    
    bool bfsvis[N];
    
    il void bfs(){
    	queue<ll> Q; bfsvis[1]=1; Q.push(1);
    	while(!Q.empty()){
    		ll u=Q.front(); Q.pop();
    		for(pii ed : E[u]){
    			ll v=ed.fi, w=ed.se;
    			if(bfsvis[v]) continue;
    			bfsvis[v]=1;
    			Q.push(v);
    		}
    	}
    	return ;
    }
    
    il ll find(ll x){
    	if(fa[x]!=x) fa[x]=find(fa[x]);
    	return fa[x];
    }
    
    il void unity(ll tx, ll ty){
    	ll fa1=find(tx), fa2=find(ty);
    	if(fa1==fa2) return ;
    	fa[fa1] = fa2;
    	return ;
    }
    
    il pii Kruscal(){
    	ll ans1=0,ans2=0;
    	sort(G+1, G+tlt+1);
    	for(ll i=1; i<=n; i++){
    		fa[i]=i;
    		if(bfsvis[i]) ans1++;
    	} 
    	for(ll i=1; i<=tlt; i++){
    		ll u=G[i].u, v=G[i].v, w=G[i].w;
    		if(find(u)==find(v)) continue;
    		unity(u, v);
    		ans2 += w;
    	}
    	return {ans1, ans2};
    }
    
    bool MEMED;
    signed main() {
    	fastio;
    	cin >> n >> m;
    	for(ll i=1; i<=n; i++) cin >> H[i];
    	for(ll i=1; i<=m; i++){
    		ll u,v,k;
    		cin >> u >> v >> k;
    		Edges[i] = {u,v,k};
    		if(H[u]>=H[v]) E[u].pb({v,k});
    		if(H[v]>=H[u]) E[v].pb({u,k});
    	}
    	bfs();
    	for(ll i=1; i<=m; i++){
    		if(bfsvis[Edges[i].u] && bfsvis[Edges[i].v]){
    			ll u=Edges[i].u, v=Edges[i].v, w=Edges[i].w;
    			if(H[u]>=H[v]) G[++tlt] = {u,v,w};
    			if(H[u]<=H[v]) G[++tlt] = {v,u,w};
    		}
    	}
    	pii ans = Kruscal();
    	printf("%lld %lld\n", ans.fi, ans.se);
    	
    	#ifdef DEBUG
    	printf("time: %lld ms\n", (ll)(((double)clock() - clock_st) * 1000.0 / CLOCKS_PER_SEC));
    	printf("memory: %.2lf MB\n", (double)abs((&MEMED - &MEMST) / 1024.0 / 1024.0));
    	#endif
    	return 0;
    }
    
    • 1

    信息

    ID
    3248
    时间
    3000ms
    内存
    256MiB
    难度
    6
    标签
    递交数
    2
    已通过
    1
    上传者