[SCOI2012]滑雪
阿新 • • 發佈:2021-01-12
題目
點這裡看題目。
分析
首先第一問非常簡單,可以直接 BFS 解決。
考慮第二問,類似於生成樹,可以暴力朱劉演算法解決顯然我們只需要對 BFS 中遇到的點和邊進行生成樹。這裡的邊需要保證有 \(h_u\ge h_v\) 。
注意到這些點是必選的,因此我們只需要保證在生成樹構建的過程中總有加入的邊是合法的,就可以把邊近似地看作無向邊。
因此可以直接對於每條邊,按照終點高度優先從高到低、邊權次之由低到高排序並進行 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; }