P8028 [COCI 2021/2022 #3] Cijanobakterije 题解
有个彩蛋
题目描述
一位微生物学家有 \(n\) 个蓝藻细菌。这些细菌中有 \(m\) 组细菌 \((a_i,b_i)\),表示 \(a_i\) 和 \(b_i\) 之间有一条生物链。若干条生物链顺次连接之后可组成长链。长链的长度定义为这条长链上的细菌数量。
现可在细菌之间两两添加若干条生物链,使得添加之后的所有生物链均不存在环。
求在进行若干次添加生物链的操作后,最长的长链的长度是多少。
输入格式
第一行,两个整数 \(n,m\)。
接下来的 \(m\) 行,每行两个正整数 \(a_i,b_i\),表示 \(a_i,b_i\) 两个细菌之间有一条生物链。数据保证 \(a_i \neq b_i\) 且同一条生物链只会出现一次,同时这 \(m\) 条生物链不会存在环。
输出格式
输出最长的长链的长度。
输入输出样例 #1
输入 #1
100 0
输出 #1
100
输入输出样例 #2
输入 #2
8 6
1 2
1 3
1 4
5 6
5 7
5 8
输出 #2
6
输入输出样例 #3
输入 #3
6 5
1 2
2 3
3 4
4 6
4 5
输出 #3
5
说明/提示
【样例 2 解释】
在 \(2\) 和 \(6\) 之间添加一条生物链后,最长的长链为 \(3-1-2-6-5-7\),长度为 \(6\)。
【数据规模与约定】
本题采用子任务捆绑测试。
- Subtask 1(15 pts):\(m=n-1\)。
- Subtask 2(6 pts):\(b_i=a_i+1\)。
- Subtask 3(6 pts):\(1 \le a_i \le 2\)。
- Subtask 4(15 pts):\(1 \le n \le 1000\)。
- Subtask 5(28 pts):无特殊限制。
对于 \(100\%\) 的数据,\(1 \le n \le 10^5\),\(0 \le m \lt n\),\(1 \le a_i,b_i \le n\)。
【提示与说明】
题目译自 COCI 2021-2022 CONTEST #3 Task 2 Cijanobakterije。
本题分值按 COCI 原题设置,满分 \(70\)。
题面很简单,就是会构建很多连通块,每个连通块都是树
题目提到最大,很容易想到树的直径,让每一个树的直径 首尾顺次相接,自然可以得到最大值
如果不知道什么是树的直径可以点链接看看题解
#include <bits/stdc++.h>
using namespace std;
constexpr int N = 1e5 + 2;
vector<int> a[N];
int d[N], fl[N];
vector<int> f;
inline void dfs(int now) {
f.push_back(now);
for (auto i : a[now]) {
if (!d[i]) {
d[i] = d[now] + 1;
dfs(i);
}
}
}
signed main() {
int n, m;
cin >> n >> m;
for (int i = 1; i <= m; i++) {
int u, v;
cin >> u >> v;
a[u].push_back(v);
a[v].push_back(u);
}
int ans = 0;
for (int i = 1; i <= n; i++) {
if (fl[i]) continue;
f.clear();
memset(d, 0, sizeof d);
d[i] = 1;
dfs(i);
int pos = 0;
int mx = 0;
for (auto j : f) {
if (d[j] > mx) {
mx = d[j];
pos = j;
}
}
f.clear();
memset(d, 0, sizeof d);
d[pos] = 1;
dfs(pos);
mx = 0;
for (auto j : f) {
mx = max(d[j], mx);
fl[j] = true;
}
ans += mx;
}
cout << ans;
return 0;
}
然后会发现\(42pts\),原来是\(memset\), 于是你加了时间戳,我甚至写了快读
#include <bits/stdc++.h>
using namespace std;
constexpr int N = 1e5 + 2;
vector<int> a[N];
int d[N][2], fl[N], t = 0;
// 0是时间点,1是值
vector<int> f;
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + (ch - '0');
ch = getchar();
}
return x * f;
}
inline void dfs(int now) {
f.push_back(now);
d[now][0] = t;
for (auto i : a[now]) {
if (d[i][0] != t) {
d[i][1] = d[now][1] + 1;
dfs(i);
}
}
}
signed main() {
int n = read(), m = read();
for (int i = 1; i <= m; i++) {
int u = read(), v = read();
a[u].push_back(v);
a[v].push_back(u);
}
int ans = 0;
for (int i = 1; i <= n; i++) {
if (fl[i]) continue;
f.clear();
d[i][1] = 1;
t++;
dfs(i);
int pos = 0;
int mx = 0;
for (auto j : f) {
if (d[j][1] > mx) {
mx = d[j][1];
pos = j;
}
}
f.clear();
d[pos][1] = 1;
t++;
dfs(pos);
mx = 0;
for (auto j : f) {
mx = max(d[j][1], mx);
fl[j] = true;
}
ans += mx;
}
cout << ans;
return 0;
}
\(nice!\),AC记录
彩蛋
不是有一个\(42pts\)代码吗?写上快读和一点优化be like:

比代码1快一点,代码1.19ms

浙公网安备 33010602011771号