[SCOI2012]滑雪

题目

点这里看题目。

分析

首先第一问非常简单,可以直接 BFS 解决。

考虑第二问,类似于生成树,可以暴力朱刘算法解决显然我们只需要对 BFS 中遇到的点和边进行生成树。这里的边需要保证有 \(h_u\ge h_v\)

注意到这些点是必选的,因此我们只需要保证在生成树构建的过程中总有加入的边是合法的,就可以把边近似地看作无向边。

因此可以直接对于每条边,按照终点高度优先从高到低、边权次之由低到高排序并进行 Kruskal 。

由于可到的点必然可以按照高度分层,因此我们实际上是在分层进行 Kruskal ,所以每次每条边的起点必然已经被加入。

小结:

利用高度带来的层的性质,将有向边转化为无向边,从而可以进行 Kruskal 。

代码

#include <cstdio>
#include <algorithm>
using namespace std;

#define rep( i, a, b ) for( int (i) = (a) ; (i) <= (b) ; ++ (i) )
#define per( i, a, b ) for( int (i) = (a) ; (i) >= (b) ; -- (i) )

typedef long long LL;

const int MAXN = 2e5 + 5, MAXM = 1e6 + 5;

template<typename _T>
void read( _T &x )
{
	x = 0; char s = getchar(); int f = 1;
	while( s < '0' || '9' < s ) { f = 1; if( s == '-' ) f = -1; s = getchar(); }
	while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ); s = getchar(); }
	x *= f;
}

template<typename _T>
void write( _T x )
{
	if( x < 0 ) putchar( '-' ), x = -x;
	if( 9 < x ) write( x / 10 );
	putchar( x % 10 + '0' );
}

template<typename _T>
void swapp( _T &x, _T &y )
{
	_T t = x; x = y, y = t;
}

struct Edge
{
	int to, nxt;
}Graph[MAXM];

struct KruEdge
{
	int u, v, w, ed;
	KruEdge() { u = v = w = 0; }
	KruEdge( int U, int V, int W ) { u = U, v = V, w = W; }
	bool operator < ( const KruEdge &b ) const { return ed == b.ed ? w < b.w : ed > b.ed; }
}E[MAXM];

int q[MAXN];

int head[MAXN], fa[MAXN], H[MAXN];
int N, M, K, cnt = 0;
bool vis[MAXN];

void MakeSet( const int siz ) { rep( i, 1, N ) fa[i] = i; }
int FindSet( const int u ) { return fa[u] = ( fa[u] == u ? u : FindSet( fa[u] ) ); }

bool UnionSet( int u, int v )
{
	u = FindSet( u ), v = FindSet( v );
	if( u == v ) return false; fa[u] = v; return true;
}

void AddEdge( const int from, const int to )
{
	Graph[++ cnt].to = to, Graph[cnt].nxt = head[from];
	head[from] = cnt;
}

int main()
{
	read( N ), read( M );
	rep( i, 1, N ) read( H[i] );
	rep( i, 1, M ) 
	{
		read( E[i].u ), read( E[i].v ), read( E[i].w );
		if( H[E[i].u] < H[E[i].v] ) continue;
		AddEdge( E[i].u, E[i].v ), E[i].ed = H[E[i].v];
	}
	int h = 1, t = 0; vis[q[++ t] = 1] = true;
	while( h <= t )
	{
		int u = q[h ++], v;
		for( int i = head[u] ; i ; i = Graph[i].nxt )
			if( ! vis[v = Graph[i].to] ) vis[q[++ t] = v] = true;
	}
	write( t ), putchar( ' ' ); LL ans = 0;
	sort( E + 1, E + 1 + M ); MakeSet( N );
	rep( i, 1, M ) 
		if( H[E[i].u] >= H[E[i].v] )
			if( vis[E[i].u] && vis[E[i].v] && UnionSet( E[i].u, E[i].v ) )
				ans += E[i].w;
	write( ans ), putchar( '\n' );
	return 0;
}
posted @ 2021-01-12 16:40  crashed  阅读(68)  评论(0编辑  收藏  举报