#include using namespace std; /* 通用模板:虚拟源点 + Kruskal 求最小生成树 适用场景: - 每个节点有一个直接购买成本 cost[i] - 节点之间有全图/部分图的额外边权 w(i,j) - 最小代价获得所有节点(最小购买成本/最小连通代价) 思想: - 新建虚拟节点 0 - 向所有节点 i 添加边 (0, i) 权重 cost[i] - 将所有边 (i, j) 加入 - 对整个图做 MST */ struct Edge { int u, v, w; bool operator < (const Edge &other) const { return w < other.w; } }; // -------------- DSU(并查集)模板 -------------- vector parent; int find(int x) { return parent[x] == x ? x : parent[x] = find(parent[x]); } bool mergeSet(int x, int y) { x = find(x); y = find(y); if (x == y) return false; parent[x] = y; return true; } // ---------------------------------------------- int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int N; // 节点数量 cin >> N; vector cost(N+1); // 每个节点的购买代价,自定义题目可按需求调整 for (int i = 1; i <= N; i++) cin >> cost[i]; vector edges; // 初始化 DSU,节点范围为 0 ~ N(N+1 个节点) parent.resize(N + 1); for (int i = 0; i <= N; i++) parent[i] = i; // Step 1:添加虚拟源点 0 的边 // 边 (0, i) 表示“直接购买第 i 个节点” for (int i = 1; i <= N; i++) { edges.push_back({0, i, cost[i]}); } // Step 2:添加原有图的边 // 例如读取 M 条边 (u, v, w) int M; cin >> M; for (int i = 0; i < M; i++) { int u, v, w; cin >> u >> v >> w; edges.push_back({u, v, w}); } // Step 3:Kruskal MST sort(edges.begin(), edges.end()); long long result = 0; int used = 0; // 已加入的边数量 for (auto &e : edges) { if (mergeSet(e.u, e.v)) { result += e.w; used++; if (used == N) break; // N+1 个节点选 N 条边即可 } } cout << result << "\n"; return 0; }