1. 程式人生 > >【生成樹,堆】【CF1095F】 Make It Connected

【生成樹,堆】【CF1095F】 Make It Connected

Description

給定 \(n\) 個點,每個點有點權,連結兩個點花費的代價為兩點的點權和。另外有 \(m\) 條特殊邊,引數為 \(x,y,z\)。意為如果你選擇這條邊,就可以花費 \(z\) 的代價將點 \(x\) 和點 \(y\) 連結起來,當然你也可以不選擇這條邊。求使整個圖聯通的最小代價

Input

第一行是兩個整數,分別是點數 \(n\) 和特殊邊的數量 \(m\)

下面一行 \(n\) 個數,第 \(i\) 個數代表點 \(i\) 的點權

下面 \(m\) 行,每行三個數 \(x,y,z\),代表一條特殊邊

Output

輸出一行一個整數,最小代價

Hint

\(1~\leq~n~\leq~2~\times~10^5~,0~\leq~m~\leq~2~\times~10^5\)

設第 \(i\) 個點的點權為 \(a_i\),第 \(j\) 條特殊邊的邊權為 \(z_j\),保證

\(1~\leq~a_i,z_j~\leq~10^{12}\)

保證特殊邊的引數 \(x~\neq~y\)

Solution

顯然這個題目是要求一個 MST (最小生成樹),但是 \(O(n^2)\) 建圖顯然不可取。

我們考慮克魯斯卡爾演算法的本質:

有若干個聯通塊,每次尋找聯通塊間權值最小的邊將之連結。

考慮對於本題來說,在不考慮特殊邊的情況下,連結兩個聯通塊,顯然要分別選擇兩個聯通塊內點權最小的點連結。於是我們對每個集合維護點權最小的點,每次取出點權前兩小的集合進行連邊即可。維護點權前兩小的集合顯然可以用一個堆做。

考慮有特殊邊怎麼辦:

我們把特殊邊排序,每次比較當前的特殊邊的權值小還是前兩個聯通塊的點權小,選擇更小的合併。

注意處理一下當前選出的兩個點在一個集合中的情況。

因為一共要做 \(O(n)\) 次,每次會有 \(O(1)\) 次對堆的插入和刪除操作,於是複雜度 \(O(n \log n)\)

Code

#include <cstdio>
#include <queue>
#include <algorithm>
#ifdef ONLINE_JUDGE
#define freopen(a, b, c)
#endif
#define rg register
#define ci const int
#define cl const long long

typedef long long int ll;

namespace IPT {
    const int L = 1000000;
    char buf[L], *front=buf, *end=buf;
    char GetChar() {
        if (front == end) {
            end = buf + fread(front = buf, 1, L, stdin);
            if (front == end) return -1;
        }
        return *(front++);
    }
}

template <typename T>
inline void qr(T &x) {
    rg char ch = IPT::GetChar(), lst = ' ';
    while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
    while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
    if (lst == '-') x = -x;
}

template <typename T>
inline void ReadDb(T &x) {
    rg char ch = IPT::GetChar(), lst = ' ';
    while ((ch > '9') || (ch < '0')) lst = ch, ch = IPT::GetChar();
    while ((ch >= '0') && (ch <= '9')) x = x * 10 + (ch ^ 48), ch = IPT::GetChar();
    if (ch == '.') {
        ch = IPT::GetChar();
        double base = 1;
        while ((ch >= '0') && (ch <= '9')) x += (ch ^ 48) * ((base *= 0.1)), ch = IPT::GetChar();
    }
    if (lst == '-') x = -x;
}

namespace OPT {
    char buf[120];
}

template <typename T>
inline void qw(T x, const char aft, const bool pt) {
    if (x < 0) {x = -x, putchar('-');}
    rg int top=0;
    do {OPT::buf[++top] = x % 10 + '0';} while (x /= 10);
    while (top) putchar(OPT::buf[top--]);
    if (pt) putchar(aft);
}

const int maxn = 200010;
const int maxm = 400010;

struct Edge {
    int from, to;
    ll v;
    inline bool operator<(const Edge &_others) const {
        return this->v < _others.v;
    }
};
Edge edge[maxm];

int n, m;
int ufs[maxn], vec[maxn], rk[maxn];
ll ans;
ll MU[maxn];

struct Zay {
    int id;
    ll v;
    inline bool operator<(const Zay &_others) const {
        return this->v > _others.v;
    }
};
std::priority_queue<Zay>Q;

int find(ci x) {return ufs[x] == x ? x : ufs[x] = find(ufs[x]);}

int main() {
    freopen("1.in", "r", stdin);
    qr(n); qr(m);
    for (rg int i = 1; i <= n; ++i) qr(MU[i]);
    for (rg int i = 1; i <= m; ++i) {
        qr(edge[i].from); qr(edge[i].to); qr(edge[i].v);
    }
    std::sort(edge + 1, edge + 1 + m);
    edge[m + 1].v = 1ll << 62;
    for (rg int i = 1; i <= n; ++i) ufs[i] = i, vec[i] = i, rk[i] = 1, Q.push((Zay){i, MU[i]});
    for (rg int i = 1, cur = 1; i < n; ++i) {
        while ((cur <= m) && (find(edge[cur].from) == find(edge[cur].to))) ++cur;
        Zay t1 = Q.top(); Q.pop(); Zay t2 = Q.top(); Q.pop();
        while (find(t1.id) == find(t2.id)) {t2 = Q.top(); Q.pop();}
        if ((t1.v + t2.v) <= edge[cur].v) {
            int fa = find(t1.id), fb = find(t2.id);
            ans += t1.v + t2.v;
            if (rk[fa] < rk[fb]) ufs[fb] = fa;
            else if (rk[fa] > rk[fb]) ufs[fa] = fb;
            else ufs[fa] = fb, ++rk[fb];
            Q.push((Zay){find(fa), t1.v});
            vec[find(fa)] = vec[fa];
        } else {
            int fa = find(edge[cur].from), fb = find(edge[cur].to);
            ans += edge[cur].v;
            if (rk[fa] < rk[fb]) ufs[fb] = fa;
            else if (rk[fa] > rk[fb]) ufs[fa] = fb;
            else ufs[fa] = fb, ++rk[fb];
            Q.push((Zay){find(fa), MU[vec[fa]]});
            vec[find(fa)] = vec[fa];
            Q.push(t1); Q.push(t2);
        }
    }
    qw(ans, '\n', true);
    return 0;
}