题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2753
题意:一个n个点m条边的带权无向图,每个点有一个高度值h。某个从1号点开始遍历,每次走的边u到v,必须满足h[u]>=h[v]。已知从当前点回到曾经遍历过的任意一个点是不需要走路的。求最多可以遍历多少个点?遍历这些点走的最小路程是多少?
思路:只记录h[u]>=h[v]的 边,因为其他边是无用的,这样其实是个有向图。首先从1BFS一次可以得到多少个点可以到达。然后将边排序,对于边<u,v,w>按照 h[v]降序排序,然后h[v]相等的按照w升序。这样用克鲁斯卡尔并查集一下就行。
struct node
{
int u,v,w,next;
};
node edges[N<<1];
int head[N],e;
void Add(int u,int v,int w)
{
edges[e].u=u;
edges[e].v=v;
edges[e].w=w;
edges[e].next=head[u];
head[u]=e++;
}
int a[N];
i64 dis[N];
int n,m,visit[N];
int cmp(node p,node q)
{
return a[p.v]>a[q.v]||a[p.v]==a[q.v]&&p.w<q.w;
}
int f[N];
int get(int x)
{
if(f[x]!=x) f[x]=get(f[x]);
return f[x];
}
i64 cal()
{
sort(edges,edges+e,cmp);
int i;
FOR1(i,n) f[i]=i;
int x,y,u,v;
i64 ans=0;
FOR0(i,e)
{
u=edges[i].u;
v=edges[i].v;
if(!visit[u]||!visit[v]) continue;
x=get(u);
y=get(v);
if(x!=y) f[x]=y,ans+=edges[i].w;
}
return ans;
}
int main()
{
RD(n,m);
int i;
FOR1(i,n) RD(a[i]);
int x,y,w;
clr(head,-1);
FOR1(i,m)
{
RD(x,y,w);
if(a[x]>=a[y]) Add(x,y,w);
if(a[y]>=a[x]) Add(y,x,w);
}
queue<int> Q;
int cnt=0;
Q.push(1);
visit[1]=1;
while(!Q.empty())
{
x=Q.front();
Q.pop();
cnt++;
for(i=head[x];i!=-1;i=edges[i].next)
{
y=edges[i].v;
if(!visit[y]) visit[y]=1,Q.push(y);
}
}
printf("%d %lld\n",cnt,cal());
}