CF196E Opening Portals
给定一个有 n n n个节点, m m m条边的无向联通图,有 k k k个点有 p o r t a l s portals portals,当经过了某个点,如果这个点有 p o r t a l portal portal,它就会永久开启,
对于任意两个开启的 p o r t a l portal portal,我们可以不需要花时间穿行,问开启所有的 p o r t a l portal portal需要多少时间。
可以考虑这是一个 1 − > S v 1->S_v 1−>Sv, S v S_v Sv是另 k k k个 p o r t a l s portals portals联通的最小生成树,
因此我们的答案就是 1 − > n e a r e s t ∈ k 1->nearest\in k 1−>nearest∈k,再加上最小生成树的代价,
我们另这 k k k个点去跑最短路,然后把原本的边 { u , v , w } \{u, v, w\} {u,v,w}变为 { n e a r e s t ∈ k o f u , n e a r e s t ∈ k o f v , d i s [ u ] + d i s [ v ] + w } \{nearest \in k\ of\ u, nearest \in k\ of\ v, dis[u] + dis[v] + w\} {nearest∈k of u,nearest∈k of v,dis[u]+dis[v]+w}
k k k点中与 u u u最近的点, k k k点中与 v v v最近的点,边权同时更新,最后只需要跑一个最小生成树计算代价即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
struct Res {
int u, v;
long long w;
void read() {
scanf("%d %d %lld", &u, &v, &w);
}
bool operator < (const Res &t) const {
return w < t.w;
}
}edge[N];
struct Node {
int u;
long long w;
bool operator < (const Node &t) const {
return w > t.w;
}
};
int n, m, k, vis[N], fa[N], pre[N];
long long dis[N];
vector< pair<int, int> > G[N];
int find(int rt) {
return rt == fa[rt] ? rt : fa[rt] = find(fa[rt]);
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
scanf("%d %d", &n, &m);
for (int i = 1; i <= m; i++) {
edge[i].read();
G[edge[i].u].push_back({edge[i].v, edge[i].w});
G[edge[i].v].push_back({edge[i].u, edge[i].w});
}
scanf("%d", &k);
priority_queue<Node> q;
memset(dis, 0x3f, sizeof dis);
for (int i = 1, x; i <= k; i++) {
scanf("%d", &x);
q.push({x, 0});
pre[x] = x;
dis[x] = 0;
}
while (q.size()) {
auto u = q.top().u;
q.pop();
if (vis[u]) {
continue;
}
vis[u] = 1;
for (auto &to : G[u]) {
if (dis[to.first] > dis[u] + to.second) {
dis[to.first] = dis[u] + to.second;
pre[to.first] = pre[u];
q.push({to.first, dis[to.first]});
}
}
}
long long ans = dis[1];
for (int i = 1; i <= m; i++) {
edge[i].w += dis[edge[i].u] + dis[edge[i].v];
edge[i].u = pre[edge[i].u], edge[i].v = pre[edge[i].v];
}
sort(edge + 1, edge + 1 + m);
for (int i = 1; i <= n; i++) {
fa[i] = i;
}
for (int i = 1, cur = 1; i <= m && cur < n; i++) {
int u = find(edge[i].u), v = find(edge[i].v);
if (u ^ v) {
cur++;
fa[u] = v;
ans += edge[i].w;
}
}
printf("%lld\n", ans);
return 0;
}