JOI 11 本選 Festivals in JOI Kingdom ( MSSP Dijkstra + Kruskal + Doubling LCA )
Festivals in JOI Kingdom | Aizu Online Judge
先に全ての町について、一番近い祭りの距離を計算する。そして、最大全域木をその最短距離に基づき作る( 祭りに近い方からと遠い方から来ても、近い方を取る )とクエリ( u, v )に対しての答えは ( u, lca( u, v ) )と ( v, lca( u, v ) )で辿る全ての辺の中の最小値だと分かる。
実装は、今の僕には重い。。。でもいい練習になった。前からずっと勘違いしてたのがDijkstraやbellman-fordは Single Source Shortest Pathしかできないと思っていたことだ。しかし、今回はDijikstraでMultiple Source やってみて同じO( E lg V )ができると悟った、始点を増やすことだけだった。
ちょっと間抜けしてできたバグは:
1。priority_queue< pii > 宣言して最短距離を計算しようとした、TLE。
2。mincost[ i ][ u ] = mincost[ i - 1 ][ u ], mincost[ i - 1 ][ mid ]; こんなことした。。。
全体的になんか
UVA 11354 Bond ( 最小瓶頸路徑 Kruskal + LCA ) - 0w1これと似てる様な感じがする。
#include <bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 5; const int MAXM = 2e5 + 5; const int MAXQ = 1e5 + 5; const int MAXL = 1e3 + 3; const int INF = 0x3f3f3f3f; const int LGN = 20 + 1; void upmin(int &x, int v){ if( x > v ) x = v; } int n, m, k, q; struct Edge{ int u, v, w; Edge(int _u = 0, int _v = 0, int _w = 0): u(_u), v(_v), w(_w){} bool operator < (const Edge &oth) const{ return w > oth.w; } } es[ MAXM * 2 ]; vector<int> G[ MAXN ]; vector<int> festival; typedef pair<int, int> pii; struct Dijkstra{ int vis[ MAXN ], dis[ MAXN ]; void init(){ // memset( vis, 0, sizeof(vis) ); memset( dis, INF, sizeof(dis) ); } void solve(){ priority_queue< pii, vector<pii>, greater<pii> > pq; for(int i = 0; i < festival.size(); ++i) // pq.push( pii( dis[ festival[ i ] ] = 0, festival[ i ] ) ); while( !pq.empty() ){ int u = pq.top().second; pq.pop(); for(int vidx: G[ u ]){ Edge &e = es[ vidx ]; if( dis[ e.v ] > dis[ u ] + e.w ){ dis[ e.v ] = dis[ u ] + e.w; pq.push( pii( dis[ e.v ], e.v ) ); } } } } } dijkstra; struct UnionFind{ int fa[ MAXN ]; void init(){ for(int i = 0; i < MAXN; ++i) fa[ i ] = i; } int find(int a){ return fa[ a ] == a ? a : fa[ a ] = find( fa[ a ] ); } bool unite(int a, int b){ int x = find( a ); int y = find( b ); if( x == y ) return false; fa[ x ] = y; return true; } } uf; vector<Edge> MST[ MAXN ]; int cost[ MAXN ]; struct Kruskal{ vector<Edge> chose; void init(){ chose.clear(); uf.init(); } void solve(){ vector<Edge> cand; for(int i = 0; i < m; ++i){ Edge &e = es[ i ]; cand.push_back( Edge( e.u, e.v, min( cost[ e.u ], cost[ e.v ] ) ) ); } sort( cand.begin(), cand.end() ); for(int i = 0; i < m; ++i){ if( uf.unite( cand[ i ].u, cand[ i ].v ) ){ chose.push_back( cand[ i ] ); MST[ cand[ i ].u ].push_back( cand[ i ] ); MST[ cand[ i ].v ].push_back( Edge( cand[ i ].v, cand[ i ].u, cand[ i ].w ) ); if( chose.size() == n - 1 ) break; } } // for(int i = 0; i < chose.size(); ++i) // printf("*chose[ %d ] : %d < - > %d = %d\n", i, chose[i].u, chose[i].v, chose[i].w); assert( chose.size() == n - 1 ); } } kruskal; struct LCA{ int anc[ LGN ][ MAXN ]; int mincost[ LGN ][ MAXN ], depth[ MAXN ]; void init(){ memset( anc, -1, sizeof(anc) ); memset( mincost, INF, sizeof(mincost) ); } void dfs(int u, int fa, int dpt){ depth[ u ] = dpt; for(Edge &e: MST[ u ]){ if( e.v == fa ) continue; // printf("anc[ %d ] : %d\n", e.v, u); anc[ 0 ][ e.v ] = u; mincost[ 0 ][ e.v ] = e.w; // printf("mincost[ %d ] : %d\n", e.v, e.w); dfs( e.v, u, dpt + 1 ); } } void preLCA(){ for(int i = 1; i < LGN; ++i) for(int u = 1; u <= n; ++u) if( anc[ i - 1 ][ u ] != -1 ){ int mid = anc[ i - 1 ][ u ]; anc[ i ][ u ] = anc[ i - 1 ][ mid ]; if( anc[ i ][ u ] == -1 ) continue; // mincost[ i ][ u ] = mincost[ i - 1 ][ u ], mincost[ i - 1 ][ mid ]; = = WT mincost[ i ][ u ] = min( mincost[ i - 1 ][ u ], mincost[ i - 1 ][ mid ] ); } } void preprocess(){ dfs( 1, -1, 0 ); preLCA(); } int qMincost(int u, int v){ int res = INF; if( depth[ u ] < depth[ v ] ) swap( u, v ); int diff = depth[ u ] - depth[ v ]; for(int i = LGN - 1; i >= 0; --i){ if( diff - ( 1 << i ) >= 0 ){ diff -= ( 1 << i ); upmin( res, mincost[ i ][ u ] ); u = anc[ i ][ u ]; } } if( u == v ) return res; for(int i = LGN - 1; i >= 0; --i) if( anc[ i ][ u ] != anc[ i ][ v ] ){ upmin( res, mincost[ i ][ u ] ); upmin( res, mincost[ i ][ v ] ); u = anc[ i ][ u ]; v = anc[ i ][ v ]; } upmin( res, mincost[ 0 ][ u ] ); upmin( res, mincost[ 0 ][ v ] ); return res; } } lca; void preSolve(){ dijkstra.init(); dijkstra.solve(); for(int i = 1; i <= n; ++i) cost[ i ] = dijkstra.dis[ i ]; kruskal.init(); kruskal.solve(); lca.init(); lca.preprocess(); } int main(){ scanf("%d%d%d%d", &n, &m, &k, &q); for(int i = 0; i < m; ++i){ int u, v, w; scanf("%d%d%d", &u, &v, &w); es[ i ] = Edge( u, v, w ); es[ m + i ] = Edge( v, u, w ); G[ u ].push_back( i ); G[ v ].push_back( m + i ); } for(int i = 0; i < k; ++i){ int p; scanf("%d", &p); festival.push_back( p ); } preSolve(); while( q-- ){ int u, v; scanf("%d%d", &u, &v); printf("%d\n", lca.qMincost( u, v )); } return 0; }