BZOJ2753: [SCOI2012]滑雪与时间胶囊

来源:互联网 发布:linux jdk gz 安装 编辑:程序博客网 时间:2024/04/28 00:33

Description

a180285非常喜欢滑雪。他来到一座雪山,这里分布着M条供滑行的轨道和N个轨道之间的交点(同时也是景点),而且每个景点都有一编号i(1<=i<=N)和一高度Hi。a180285能从景点i 滑到景点j 当且仅当存在一条i 和j 之间的边,且i 的高度不小于j。 与其他滑雪爱好者不同,a180285喜欢用最短的滑行路径去访问尽量多的景点。如果仅仅访问一条路径上的景点,他会觉得数量太少。于是a180285拿出了他随身携带的时间胶囊。这是一种很神奇的药物,吃下之后可以立即回到上个经过的景点(不用移动也不被认为是a180285 滑行的距离)。请注意,这种神奇的药物是可以连续食用的,即能够回到较长时间之前到过的景点(比如上上个经过的景点和上上上个经过的景点)。 现在,a180285站在1号景点望着山下的目标,心潮澎湃。他十分想知道在不考虑时间
胶囊消耗的情况下,以最短滑行距离滑到尽量多的景点的方案(即满足经过景点数最大的前提下使得滑行总距离最小)。你能帮他求出最短距离和景点数吗?

Input

输入的第一行是两个整数N,M。
接下来1行有N个整数Hi,分别表示每个景点的高度。
接下来M行,表示各个景点之间轨道分布的情况。每行3个整数,Ui,Vi,Ki。表示
编号为Ui的景点和编号为Vi的景点之间有一条长度为Ki的轨道。

Output

 
输出一行,表示a180285最多能到达多少个景点,以及此时最短的滑行距离总和。 

Sample Input


3 3
3 2 1
1 2 1
2 3 1
1 3 10

Sample Output

3 2

HINT

【数据范围】 

    对于30%的数据,保证 1<=N<=2000 

    对于100%的数据,保证 1<=N<=100000 

对于所有的数据,保证 1<=M<=1000000,1<=Hi<=1000000000,1<=Ki<=1000000000。

Source

第一问随便bfs水过去
第二问就是有向边的最小生成树
考虑高度限制实际就相当于分层 那么我们可以对于每一层跑最小生成树
#include <bits/stdc++.h>using namespace std;const int maxn = 100010;const int maxm = 2000020;int q[maxn],ql,qr,head[maxn],cnt,h[maxn],n,m,ans,f[maxn];long long ret;bool vis[maxn];inline int read(){int tmp = 0;char ch = getchar();while( ch < '0' || ch > '9' ) ch = getchar();while( ch >= '0' && ch <= '9' ) tmp = tmp * 10 + ch - '0' , ch = getchar();return tmp;}int findfa(int x) { return f[ x ] == x ? x : f[ x ] = findfa( f[ x ]); }struct edge{int to,nxt,val;}e[maxm];struct Edge{int u,v,w;bool operator < (const Edge a ) const {return h[ v ] == h[ a.v ] ? w < a.w : h[ v ] > h[ a.v ];}}g[maxm];inline void addedge(int x,int y,int w){e[ ++cnt ].to = y;e[ cnt ].nxt = head[ x ];head[ x ] = cnt;e[ cnt ].val =  w;}inline void bfs(){q[ ++qr ] = 1;ans = 1;vis[ 1 ] = true;while( ql < qr ){int x = q[ ++ql ];for( int i = head[ x ] ; i ; i = e[ i ].nxt ){g[ ++m ] = ( Edge ){ x, e[ i ].to , e[ i ].val };if( !vis[ e[ i ].to ])vis[ e[ i ].to ] = 1,ans ++, q[ ++qr ] = e[ i ].to;}}}int main(){n = read(), m =read();for( int i = 1 ; i <= n ; i++ ) h[ i ] = read(),f[ i ] = i;for( int i = 1 ; i <= m ; i++ ){int x = read(), y = read(), w = read();if( h[ x ] >= h[ y ] ) addedge(x,y,w);if( h[ y ] >= h[ x ] ) addedge(y,x,w);}m = 0;bfs();sort(g+1,g+m+1);for( int i = 1 ; i <= m ; i++ )if( findfa(g[ i ].u)!=findfa(g[ i ].v) )ret+=g[ i ].w,f[findfa(g[ i ].u)] = findfa(g[ i ].v);return printf("%d %lld\n",ans,ret),0;}


0 0