题目描述
A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
输入
第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道路。
接下来 m 行每行 3 个整数 x、y、z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意:x 不等于 y,两座城市之间可能有多条道路。
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y。
输出
输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出-1。
样例输入
4 3
1 2 42 3 333 1 11 31 3
1 4
样例输出
3
-1
3
提示
对于 30%的数据,0 < n < 1,000,0 < m < 10,000,0 < q < 1,000;对于 60%的数据,0 < n < 1,000,0 < m < 50,000,0 < q < 1,000;
对于 100%的数据,0 < n < 10,000,0 < m < 50,000,0 < q < 30,000,0 ≤ z ≤ 100,000。
题解:倍增LCA
先求出图中的最大生成树,两点间路径上的最小边(即瓶颈边)的权值为答案
f[i][j]记录节点i的第2^j个祖先,g[i][j]记录节点到第2^j个祖先上的瓶颈边;
在倍增法求LCA的过程中同步记录路径最小值即可。
#include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; const int INF=0x3f3f3f3f; const int N=10010; const int M=50010; const int LOG=25; int n, m, q, ans; void Getin( int &shu ) { char c; int f=1; shu=0; for( c=getchar(); c<'0' || c>'9'; c=getchar() ) if( c=='-' ) f=-1; for( ; c>='0' && c<='9'; c=getchar() ) shu=shu*10+c-'0'; shu*=f; } int fir[N], ecnt; struct node{ int e, w, next; }edge[N<<1]; void Link( int s, int e, int w ) { edge[++ecnt].e=e; edge[ecnt].w=w; edge[ecnt].next=fir[s]; fir[s]=ecnt; edge[++ecnt].e=s; edge[ecnt].w=w; edge[ecnt].next=fir[e]; fir[e]=ecnt; } struct nodes{ int s ,e, w; }road[M]; bool cmp( nodes a, nodes b ) { return a.w>b.w; } int h[N], rt[N]; int Root( int x ) { while( rt[x] ) x=rt[x]; return x; } void Kruskal() { sort( road+1, road+m+1, cmp ); for( int i=1; i<=m; i++ ) { int s1=road[i].s, t1=Root(s1); int s2=road[i].e, t2=Root(s2); if( t1!=t2 ) { Link( s1, s2, road[i].w ); if( h[t1]<h[t2] ) rt[t1]=t2; else rt[t2]=t1; if( h[t1]==h[t2] ) h[t1]++; } } } int fa[N][LOG+5], g[N][LOG+5], dep[N]; void DFS( int r, int f, int d ) { dep[r]=d; for( int i=fir[r]; i; i=edge[i].next ) if( edge[i].e!=f ) { fa[edge[i].e][0]=r; g[edge[i].e][0]=edge[i].w; DFS( edge[i].e, r, d+1 ); } } void Build() { for( int i=1; i<=n; i++ ) if( !rt[i] ) DFS( i, -1, 1 ); for( int j=1; j<=LOG; j++ ) for( int i=1; i<=n; i++ ) { fa[i][j]=fa[ fa[i][j-1] ][j-1]; g[i][j]=min( g[i][j-1], g[ fa[i][j-1] ][j-1] ); } } int getk( int r ,int k ) { for( int i=0; i<=LOG; i++ ) if( k&( 1<<i ) ) { ans=min( ans, g[r][i] ); r=fa[r][i]; } return r; } int getd( int r, int d ) { return getk( r, dep[r]-d ); } int p1, p2; int LCA_Find() { ans=INF; if( dep[p1]<dep[p2] ) swap( p1, p2 ); p1=getd( p1, dep[p2] ); if( p1==p2 ) return ans; for( int i=LOG; i>=0; i-- ) if( fa[p1][i]!=fa[p2][i] ) { ans=min( ans, min( g[p1][i], g[p2][i] ) ); p1=fa[p1][i]; p2=fa[p2][i]; } return min( ans, min( g[p1][0], g[p2][0] ) ); } int main() { Getin(n); Getin(m); for( int i=1; i<=m; i++ ) Getin( road[i].s ), Getin( road[i].e ), Getin( road[i].w ); Kruskal(); Build(); Getin(q); for( int i=1; i<=q; i++ ) { Getin( p1 ); Getin( p2 ); if( Root(p1)!=Root(p2) ) printf( "-1\n" ); else printf( "%d\n", LCA_Find() ); } return 0; }
[NOIP2013]货车运输
最新推荐文章于 2019-09-02 17:19:20 发布