2025.03.19 CW 模拟赛 A. 前端
A. 前端
题意
你是一个前端程序员。有一天同事来问你这个问题:
有一张 \(n\) 个点 \(m\) 条边的简单无向图, 每个点有一个正整数的权值. 现在有人打算按一个顺序依次删除这 \(n\) 个点.
定义一个连通块的权值为连通块内所有点的权值的和. 他想要知道, 每次删除了一个点之后, 图中所有连通块权值的最大值. 如果图中已经不存在连通块了, 则输出 0.
思路
正难则反, 我们倒着考虑.
这样, 我们的操作就变成
- 加入一个点
- 将该点和其的出边中已经出现过的点连起来.
这样, 我们使用并查集维护当前的连通块, 由于点权是正数, 所以权值一定会越来越大, 每次 \(\rm{merge}\) 操作的时候取 \(\max\) 即可.
#include <iostream>
#include <vector>
using namespace std;
#define int long long
constexpr int N = 1e5 + 5;
int n, m, fa[N], p[N], w[N], ans[N], mx;
bool vis[N];
vector<int> e[N];
int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
void merge(int x, int y) {
x = find(x), y = find(y);
if (x ^ y) {
w[x] += w[y];
mx = max(mx, w[x]);
fa[y] = x;
}
}
void init() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
cin >> w[i];
fa[i] = i;
}
for (int i = 1, u, v; i <= m; ++i) {
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
for (int i = n; i; --i) {
cin >> p[i];
}
}
void calculate() {
for (int i = 1; i <= n; ++i) {
ans[i] = mx;
for (int j : e[p[i]]) {
if (!vis[j]) {
continue;
}
merge(p[i], j);
}
mx = max(mx, w[find(p[i])]);
vis[p[i]] = true;
}
for (int i = n; i; --i) {
cout << ans[i] << '\n';
}
}
void solve() {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
init();
calculate();
}
signed main() {
solve();
return 0;
}

浙公网安备 33010602011771号