题目
分析
给 s s s 的邻接边弄一个 Δ \Delta Δ 值加在边权上,然后做最小生成树,易知 Δ \Delta Δ 越大, s s s 的度越小,因此可以 WQS 二分。实现把 s s s 的邻接边和非邻接边分别排好序,做的时候归并即可。
代码
#include <bits/stdc++.h>
int Read() {
int x = 0; bool f = false; char c = getchar();
while (c < '0' || c > '9')
f |= c == '-', c = getchar();
while (c >= '0' && c <= '9')
x = x * 10 + (c ^ 48), c = getchar();
return f ? -x : x;
}
typedef std::pair<int, int> PII;
const int MAXN = 50000;
const int MAXM = 500000;
const int INF = 0x3f3f3f3f;
int N, M, S, K;
struct Edge {
int u, v, w;
} E1[MAXM + 5], E2[MAXM + 5], E[MAXM + 5];
int Cnt1, Cnt2, Cnt;
inline bool Comp(const Edge &i, const Edge &j) {
return i.w < j.w;
}
void MergeSort(const int &dlt) {
Cnt = 0;
int i = 1, j = 1;
while (i <= Cnt1 && j <= Cnt2) {
if (E1[i].w + dlt < E2[j].w)
E[++Cnt] = E1[i++], E[Cnt].w += dlt;
else E[++Cnt] = E2[j++];
}
while (i <= Cnt1)
E[++Cnt] = E1[i++], E[Cnt].w += dlt;
while (j <= Cnt2)
E[++Cnt] = E2[j++];
}
int Par[MAXN + 5];
int Find(const int &u) {
return Par[u] == u ? u : (Par[u] = Find(Par[u]));
}
PII Kruscal(const int &dlt) {
MergeSort(dlt);
for (int i = 1; i <= N; i++)
Par[i] = i;
PII ret(0, 0);
// puts("");
for (int i = 1; i <= Cnt; i++) {
int u = E[i].u, v = E[i].v;
// printf("%d %d\n", u, v);
if (Find(u) != Find(v)) {
Par[Find(u)] = Find(v);
ret.first += E[i].w;
ret.second += u == S || v == S;
}
}
return ret;
}
int main() {
N = Read(), M = Read(), S = Read(), K = Read();
for (int i = 1; i <= M; i++) {
int u = Read(), v = Read(), w = Read();
if (u == S || v == S)
E1[++Cnt1] = { u, v, w };
else E2[++Cnt2] = { u, v, w };
}
std::sort(E1 + 1, E1 + Cnt1 + 1, Comp);
std::sort(E2 + 1, E2 + Cnt2 + 1, Comp);
int lft = -INF, rgt = INF;
while (lft + 1 < rgt) {
int mid = (lft + rgt) >> 1;
PII cur = Kruscal(mid);
if (cur.second < K)
rgt = mid;
else lft = mid;
}
PII cur = Kruscal(lft);
if (cur.second != K)
puts("Impossible");
else printf("%d\n", cur.first - lft * K);
return 0;
}