最小生成树
因为可以无限制地使用时间胶囊,所以第一问直接BFS跑跑就行啦
第二问的话对边按高度为第一关键字,权值为第二关键字排个序,然后Kruskal乱搞一下就行啦
注意:
对边排序时应该按目标节点的高度排序。因为建边时就已经保证初始节点的高度大于等于目标节点,这样排的话就可以保证初始节点已经被做过,不会让程序乱跑。反正50秒时间很充裕。(洛谷的时限1s简直有毒)(貌似现在改5秒了,于是我就A了)。
贴上代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 100000
#define MAXM 1000000
using namespace std;
struct edge{
int now;
int next;
int to;
int dis;
};
int k,n,m,u,v,d,num;
long long ans=0;
edge a[2*MAXM+5];
int b[MAXN+5],que[MAXN+5],father[MAXN+5],h[MAXN+5];
bool f[MAXN+5];
void bfs(){
int r=0,w=1;
que[1]=1; f[1]=true; num=1;
while (r<w){
int x=que[++r];
for (int i=h[x];i;i=a[i].next){
if (!f[a[i].to]){
que[++w]=a[i].to;
num++;
f[a[i].to]=true;
}
}
}
}
void read(int x,int y,int z){
k++; a[k].now=x; a[k].next=h[x]; a[k].to=y; a[k].dis=z;
h[x]=k;
}
bool comp(edge x,edge y){
if ((b[x.to]>b[y.to])||(b[x.to]==b[y.to]&&x.dis<y.dis))
return true;
return false;
}
int findfather(int x){
if (x==father[x])
return x;
else{
father[x]=findfather(father[x]);
return father[x];
}
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++){
scanf("%d",&b[i]);
father[i]=i;
}
for (int i=1;i<=m;i++){
scanf("%d%d%d",&u,&v,&d);
if (b[u]>=b[v]) read(u,v,d);
if (b[v]>=b[u]) read(v,u,d);
}
bfs();
printf("%d ",num);
sort(a+1,a+k+1,comp);
for (int i=1;i<=k;i++){
if (!f[a[i].now]||!f[a[i].to])
continue;
int fx=findfather(a[i].now),fy=findfather(a[i].to);
if (fx!=fy){
father[fx]=fy;
ans+=a[i].dis;
}
}
printf("%lld\n",ans);
return 0;
}