【2021牛客寒假第六场】H-动态最小生成树 线段树优化Kruskal

传送门:https://ac.nowcoder.com/acm/contest/9986/H 这一题大部分人都是暴力Kruskal冲过去的,额,应该是全部,但这显然不是最优解。

题意

题意就像题目一样,动态修改和查找最小生成树。 两个操作:

  • 修改第x条边的连接点和边权
  • 查询[l,r]所在边组成的最小生成树大小,有则输出,没有输出impossible

思路

看到最小生成树,就知道可以用Kruskal求解。 修改还是修改,不过查询的时候就要用一次Kruskal,遇到及其恶心的数据铁T。 因为Kruskal的复杂度是和边数m有关的。

看到n只有200,m有30000,所以能不能把复杂度往n上靠?答案是可以的。

区间问题?线段树!

线段树维护什么呢?针对每一个节点,我们维护一个数组,这个数组里保存的是生成树的边的集合。

所以我们建树是build(1,1,m),根据边建树,而不是点。

每次更新的时候都要重新组织最小生成树并保存,就是代码中的$push_up$。

Code

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
##include "bits/stdc++.h"

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<double, double> pdd;
typedef pair<ll, ll> pll;

##define endl "\n"
##define eb emplace_back
##define mem(a, b) memset(a , b , sizeof(a))

const ll INF = 0x3f3f3f3f;
const ll mod = 998244353;
// const ll mod = 1e9 + 7;
const double eps = 1e-6;
const double PI = acos(-1);
const double R = 0.57721566490153286060651209;

const int N = 1e5 + 10;

int n, m, q;

struct Edge {
int u, v, w;
}e[N];

##define lc t[u].l
##define rc t[u].r

struct Tree {
int l, r;
int a[505];
}t[N];
int tot = 1;
int f[N];

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

void push_up(int s, int u, int v) {
int x = 1, y = 1, z = 1;
for(int i = 1;i <= n; i++) f[i] = i, t[s].a[i] = 0;
while((t[u].a[x] t[v].a[y]) && z < n) {
if(e[t[u].a[x]].w < e[t[v].a[y]].w) {
int U = find(e[t[u].a[x]].u);
int V = find(e[t[u].a[x]].v);
if(U != V) {
f[U] = V;
t[s].a[z++] = t[u].a[x];
}
x++;
}
else {
int U = find(e[t[v].a[y]].u);
int V = find(e[t[v].a[y]].v);
if(U != V) {
f[U] = V;
t[s].a[z++] = t[v].a[y];
}
y++;
}
}
}

void build(int u, int l, int r) {
if(l == r) {
t[u].a[1] = l;
return ;
}
int mid = (l + r) / 2;
t[u].l = ++tot; t[u].r = ++tot;
build(lc, l, mid);
build(rc, mid + 1, r);
push_up(u, lc, rc);
}

void modify(int u, int l, int r, int p) {
if(l == r) return ;
int mid = (l + r) / 2;
if(p <= mid) modify(lc, l, mid, p);
else modify(rc, mid + 1, r, p);
push_up(u, lc, rc);
}

void query(int u, int l, int r, int ql, int qr) {
if(ql <= l && r <= qr) {
push_up(tot + 2, tot + 1, u);
memcpy(t[tot + 1].a, t[tot + 2].a, 4 * (n + 1));
return ;
}
int mid = (l + r) / 2;
if(ql <= mid) query(lc, l, mid, ql, qr);
if(qr > mid) query(rc, mid + 1, r, ql, qr);
}

void solve() {
scanf("%d%d%d",&n,&m,&q);
e[0].w = INF;
for(int i = 1;i <= m; i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
build(1, 1, m);
while(q--) {
int opt; scanf("%d",&opt);
if(opt == 1) {
int x, y, z, w; scanf("%d%d%d%d",&x,&y,&z,&w);
e[x].u = y; e[x].v = z; e[x].w = w;
modify(1, 1, m, x);
}
else {
int l, r; scanf("%d%d",&l,&r);
if(r - l + 1 < n - 1) {
printf("Impossible\n");
continue;
}
for(int i = 1;i <= n; i++) {
t[tot + 2].a[i] = t[tot + 1].a[i] = 0;
}
query(1, 1, m, l, r);
if(!t[tot + 1].a[n - 1]) {
printf("Impossible\n");
}
else {
int ans = 0;
for(int i = 1;i < n; i++) ans += e[t[tot + 1].a[i]].w;
printf("%d\n",ans);
}
}
}
}

signed main() {
ios_base::sync_with_stdio(false);
// cin.tie(nullptr);
// cout.tie(nullptr);
##ifdef FZT_ACM_LOCAL
freopen("../in.txt", "r", stdin);
freopen("../out.txt", "w", stdout);
signed test_index_for_debug = 1;
char acm_local_for_debug = 0;
do {
if (acm_local_for_debug == '$') exit(0);
if (test_index_for_debug > 20)
throw runtime_error("Check the stdin!!!");
auto start_clock_for_debug = clock();
solve();
auto end_clock_for_debug = clock();
cout << "Test " << test_index_for_debug << " successful" << endl;
cerr << "Test " << test_index_for_debug++ << " Run Time: "
<< double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl;
cout << "--------------------------------------------------" << endl;
} while (cin >> acm_local_for_debug && cin.putback(acm_local_for_debug));
##else
solve();
##endif
return 0;
}

本文作者:jujimeizuo
本文地址https://blog.jujimeizuo.cn/2021/02/24/2021-nowcoder-hanjia-6-h/
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0 协议。转载请注明出处!