题解:P17724 [SCP-S 2026] 路短最 / path
场上大战这个题两个小时失败,写篇题解。
手玩样例感受一下,Artskjid 相对于一个 BFS 更像 DFS。当遍历的对象是没有环时,遍历的方式是唯一的,
当出现环,会发生什么事呢?对于一个长度为
不难发现,当若干个环拼在一起的时候,可以将一个问题划分成若干子问题来结局。假如说某个环上,点
考虑建一个类似圆方树的东西(从
这是我的赛时做法,显然假了。如果把这个做法写出来,就会发现一大堆五元环嵌套的情况下,
举个例子:对于五元环
思考一下,发现错误的算法可以在这个反例是继续修改。不妨设,当前
当
考虑对每个环上的
- 若
w_y=0 。
对于任意的
- 若
w_y\ne 0 。
若
不难发现两种情况可以统一起来,得到最终的转移式:
最后记得
不难发现这个转移等价于将
考虑维护
最后只需要求出来一个
先前提到过,
从上面的转移,可以得出
我们像长链剖分一样分析复杂度:
对于空间复杂度:即所有长链的长度之和,不难发现每个叶子都会贡献
对于时间复杂度:跨过轻边的代价等价于所有长链的长度之和,上面已证明为
综上,在
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e5 + 10;
int n, m, son[N], md[N];
int Fa[N], de[N], w[N];
int st[N], tot;
vector<int> F[N], G[N];
ll f[N << 1], ans;
void clear() {
for (int i = 1; i <= n; i++) {
F[i].clear(), G[i].clear();
Fa[i] = de[i] = w[i] = st[i] = 0;
son[i] = md[i] = 0;
}
for (int i = 0; i <= tot + 1; i++) f[i] = 0;
ans = tot = 0;
return;
}
void link(int x, int y) {
F[x].push_back(y);
}
void dfs1(int x, int fa) {
de[x] = de[fa] + 1, Fa[x] = fa;
for (auto y : F[x]) {
if (y == fa) continue;
if (de[y] && de[y] < de[x]) {
vector<int> son;
for (int i = x; i != y; i = Fa[i]) son.push_back(i);
int len = son.size() + 1;
if (son[0] > son.back()) reverse(son.begin(), son.end());
for (int i = 0; i < son.size(); i++) {
Fa[son[i]] = y;
if (i >= len / 2 && i != son.size() - 1) {
w[son[i]] = i - (len - 2 - i);
}
}
} else if (!de[y]) dfs1(y, x);
}
return;
}
void add(int x, int y) {
G[x].push_back(y);
}
void dfs2(int x) {
for (auto y : G[x]) {
dfs2(y);
if (md[y] + w[y] > md[x]) {
md[x] = md[y] + w[y];
son[x] = y;
}
}
md[x] = max(md[x], 1);
return;
}
void dfs3(int x) {
if (!son[x]) { f[st[x]] += 1; return; }
int y = son[x]; st[y] = st[x] + w[y]; dfs3(y);
for (int i = 0; i < min(w[y], md[y]); i++) f[st[x] + i] = f[st[y] + i];
for (auto y : G[x]) if (y != son[x]) {
st[y] = tot, tot += md[y]; dfs3(y);
if (!w[y]) {
for (int i = 0; i < md[y]; i++) f[st[x] + i] += f[st[y] + i];
} else {
for (int i = 0; i < md[y]; i++) f[st[x] + i + w[y]] += f[st[y] + i];
for (int i = 0; i < min(md[y], w[y]); i++) f[st[x] + i] += f[st[y] + i];
}
}
f[st[x]] += 1;
return;
}
void work() {
cin >> n >> m;
for (int i = 1, u, v; i <= m; i++) {
cin >> u >> v;
link(u, v), link(v, u);
}
dfs1(1, 0);
for (int i = 2; i <= n; i++) add(Fa[i], i);
dfs2(1); st[1] = 0, tot = md[1]; dfs3(1);
for (int i = 0; i < md[1]; i++) ans += f[i];
cout << ans << '\n';
return;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int c, T; cin >> c >> T;
while (T--) work(), clear();
return 0;
}
如有错误,请指出。