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

Time Limit: 50 Sec Memory Limit: 128 MB
Submit: 3481 Solved: 1268
[Submit][Status][Discuss]

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。


看似是一个最小树形图。但是我们除了有向边还存在无向边。所以我们可以采用最小生成树的分层图思想,对于每一层跑mst,就可以解决有向边的问题了。

所以我们排序的规则为:优先对每一层来跑mst,所以例如u->v的边,我们优先v的高度排序,然后按照权值排序。就可以优先每一层,然后不同层了。

因为我们要从第一个点开始,所以我们要先从起点1开始bfs,找到能够到达的点,确定可以选择的边(有些边可能不能从1号点到达)


AC代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int n,m,h[N],cnt,f[N],res1,res2,id,vis[N];
struct node{int u,v,w;}t[N*20]; vector<int> v[N];
int cmp(node a,node b){return h[a.v]==h[b.v]?a.w<b.w:h[a.v]>h[b.v];}
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
void mst(){
	for(int i=1,x,y;i<=cnt;i++){
		if(!vis[t[i].u]||!vis[t[i].v])	continue;
		x=find(t[i].u),y=find(t[i].v);
		if(x!=y)	f[x]=y,res2+=t[i].w;
	}
}
void bfs(){
	queue<int>	q;	q.push(1);	vis[1]=res1=1;
	while(q.size()){
		int u=q.front();	q.pop();
		for(int i=0;i<v[u].size();i++){
			int to=v[u][i];
			if(!vis[to])	vis[to]=1,q.push(to),res1++;
		}
	}	
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++)	scanf("%lld",&h[i]),f[i]=i;
	for(int i=1,a,b,c;i<=m;i++){
		scanf("%lld %lld %lld",&a,&b,&c);
		if(h[a]>=h[b])	t[++cnt]={a,b,c},v[a].push_back(b);
		if(h[b]>=h[a])	t[++cnt]={b,a,c},v[b].push_back(a);
	}
	bfs();	sort(t+1,t+1+cnt,cmp);	mst();
	cout<<res1<<' '<<res2<<'\n';
	return 0;
}