2023.9.25记录
做了做并查集
[JSOI2008] 星球大战
JSOI2008] 星球大战 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题意
给定一个无向图,每次操作删除一个点,求每次操作后连通块的数量。
思路
可以用并查集做。按操作顺序不好计算连通块的数量,所以可以考虑按操作的逆向顺序计算。
因为每两个连通块相连会使连通块的数量减一,所以在计算出所有节点被删除后的连通块数量后,再按反向顺序往并查集里加入节点,此时新加入的节点就是一个连通块,所以连通块数量加一。然后检查该节点与值相邻的节点,如果相邻节点已经在并查集中且与该节点不在一个连通块里,则连通块的数量减一。
代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
class DSU {
private:
vector<int> p, siz;
public:
DSU(int n) {
init(n);
}
void init(int n) {
p.resize(n);
iota(p.begin(), p.end(), 0);
siz.assign(n, 1);
}
int find(int x) {
int t = x;
while(x != p[x]) {
x = p[x] = p[p[x]];
}
return p[t] = x;
}
bool merge(int u, int v) {
int x = find(u);
int y = find(v);
if(x == y) {
return false;
}
siz[x] += siz[y];
p[y] = x;
return true;
}
bool same(int x, int y) {
return find(x) == find(y);
}
int size(int x) {
return siz[find(x)];
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<vector<int>> adj(n);
for(int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
int k;
cin >> k;
vector<int> isBroken(n), broken(k);
for(int i = 0; i < k; i++) {
cin >> broken[i];
isBroken[broken[i]] = true;
}
DSU D(n);
int res = n - k;
for(int u = 0; u < n; u++) {
for(int v : adj[u]) {
if(isBroken[u] || isBroken[v]) {
continue;
}
if(D.merge(u, v)) {
res -= 1;
}
}
}
vector<int> ans(k + 1);
ans[k] = res;
for(int i = k - 1; i >= 0; i--) {
int u = broken[i], cnt = 0;
for(int v : adj[u]) {
if(isBroken[v]) {
continue;
}
if(D.merge(u, v)) {
cnt += 1;
}
}
isBroken[u] = false;
res -= cnt - 1;
ans[i] = res;
}
for(int x : ans) {
cout << x << "\n";
}
return 0;
}
[NOIP2010 提高组] 关押罪犯
NOIP2010 提高组] 关押罪犯 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题意
给定一个带权无向图,分为两个连通块,使得这两个连通块中最大的边权最小。
思路
把所有边按权值从大到小排序,然后从大到小判断。
如果这条边的两个端点已在同一个集合中,则这条边的边权就是答案。否则再按端点判断,如果其中一个端点的另一条边已经出现过,就把另一个端点与另一条边另一个端点合并。
代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
class DSU {
private:
vector<int> p, siz;
public:
DSU(int n) {
init(n);
}
void init(int n) {
p.resize(n);
iota(p.begin(), p.end(), 0);
siz.assign(n, 1);
}
int find(int x) {
int t = x;
while(x != p[x]) {
x = p[x] = p[p[x]];
}
return p[t] = x;
}
bool merge(int u, int v) {
int x = find(u);
int y = find(v);
if(x == y) {
return false;
}
siz[x] += siz[y];
p[y] = x;
return true;
}
bool same(int x, int y) {
return find(x) == find(y);
}
int size(int x) {
return siz[find(x)];
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<array<int, 3>> v(m);
for(int i = 0; i < m; i++) {
cin >> v[i][0] >> v[i][1] >> v[i][2];
}
sort(v.begin(), v.end(), [&](array<int, 3> &a, array<int, 3> &b) {
return a[2] > b[2];
});
DSU D(n + 1);
vector<int> e(n + 1);
for(auto [u, v, w] : v) {
if(D.same(u, v)) {
cout << w << "\n";
return 0;
}
e[u] ? D.merge(e[u], v) : e[u] = v;
e[v] ? D.merge(e[v], u) : e[v] = u;
}
cout << 0 << "\n";
return 0;
}

浙公网安备 33010602011771号