P2573 [SCOI2012] 滑雪

黑屿白發表於2024-05-03

原題連結

題解

這題乍一看好像是一道最小生成樹的模板題,但如果直接找模板打會發現WA。

仔細一看這題是有向圖的最小生成樹,可以直接套朱劉演算法,but,我還不會······

直接套模板的反例

3
3 2 1
1 2 5
1 3 2
2 3 1

所以我們再分析題目,發現只要把山的高度設為第一優先順序,邊的權值為第二優先順序,再建樹即可。

code

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
const int M=2e6+5;
typedef long long ll;
int head[N],Next[M],to[M],h[N],weight[M];
bool vis[N];
int n,m,cnt=1,sum=0;
ll pre=0;
struct node{
    int id,value;
    bool operator <(const node &a)const{
        if (h[id]!=h[a.id]) return h[id]<h[a.id];
        return value>a.value;
    }
};
void build(int from,int to_,int w){
    Next[cnt]=head[from];
    to[cnt]=to_;
    weight[cnt]=w;
    head[from]=cnt++;
}
void prim(int from){
    priority_queue<node> que;
    node x;
    x.id=from;
    x.value=0;
    que.push(x);
    while (!que.empty()){
        x=que.top();
        que.pop();
        if (vis[x.id]) continue;
        else vis[x.id]=true;
        sum++;
        pre+=x.value;
        for (int i=head[x.id];i>0;i=Next[i]){
            node y;
            y.id=to[i];
            y.value=weight[i];
            que.push(y);
        }
    }
}
int main(){
    cin>>n>>m;
    for (int i=1;i<=n;i++){
        cin>>h[i];
    }
    for (int i=1;i<=m;i++){
        int a,b,c;
        cin>>a>>b>>c;
        if (h[a]>=h[b]) build(a,b,c);
        if (h[a]<=h[b]) build(b,a,c);
    }
    prim(1);
    cout<<sum<<" "<<pre;
    return 0;
}