Blog of RuSun

\begin {array}{c} \mathfrak {One Problem Is Difficult} \\\\ \mathfrak {Because You Don't Know} \\\\ \mathfrak {Why It Is Diffucult} \end {array}

P5633 最小度限制生成树

P5633 最小度限制生成树

P2619 [国家集训队]Tree I 类似。注意判断无解。几种无解的情况:

  • 所有的连接 $s$ 的边的数量小于 $k$ ;
  • 选择了所有的黑色边,但连通块的数量大于 $k + 1$ ,这意味着再选择 $k$ 条白色边后连通块的数量至少大于 $1$ ,即图不连通;
  • 所有的边都选择,图不连通。
查看代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 5e4 + 10, M = 5e5 + 10;
int n, m, s, k, p[N];
struct Edge
{
int u, v, w;
bool operator<(const Edge &_) const
{
return w < _.w;
}
};
vector<Edge> e[2];
int fa(int x)
{
return x == p[x] ? x : p[x] = fa(p[x]);
}
bool add(Edge x)
{
if (fa(x.u) == fa(x.v))
return false;
p[p[x.u]] = p[x.v];
return true;
}
bool check()
{
for (int i = 1; i <= n; i++)
p[i] = i;
int ans = n;
for (Edge i : e[1])
ans -= add(i);
if (ans - k > 1)
return true;
for (Edge i : e[0])
ans -= add(i);
return ans > 1;
}
int main()
{
scanf("%d%d%d%d", &n, &m, &s, &k);
for (int u, v, w; m; m--)
{
scanf("%d%d%d", &u, &v, &w);
e[v != s && u != s].push_back((Edge){u, v, w});
}
if (e[0].size() < k || check())
{
puts("Impossible");
return 0;
}
sort(e[0].begin(), e[0].end());
sort(e[1].begin(), e[1].end());
int l = -3e4, r = 3e4;
while (l < r)
{
int mid = l + r + 1 >> 1;
for (int i = 1; i <= n; i++)
p[i] = i;
int x = 0, y = 0, ans = 0;
while (x < e[0].size() && y < e[1].size())
e[0][x].w + mid <= e[1][y].w ? ans += add(e[0][x++]) : add(e[1][y++]);
while (x < e[0].size())
ans += add(e[0][x++]);
ans < k ? r = mid - 1 : l = mid;
}
for (int i = 1; i <= n; i++)
p[i] = i;
int x = 0, y = 0;
long long ans = 0;
while (x < e[0].size() && y < e[1].size())
if (e[0][x].w + l <= e[1][y].w)
ans += (e[0][x].w + l) * add(e[0][x]), x++;
else
ans += e[1][y].w * add(e[1][y]), y++;
while (x < e[0].size())
ans += (e[0][x].w + l) * add(e[0][x]), x++;
while (y < e[1].size())
ans += e[1][y].w * add(e[1][y]), y++;
printf("%lld\n", ans - k * l);
return 0;
}