基环树处理方法
无向基环树找环,遍历模板:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
int n;
vector<int> e[500005];
bool vis[500005] = {}, stk[500005] = {}, cir[500005] = {};
//stk是搜索栈,作用是避免在找环时从up找到了一条去dn的边,导致up以为自己的nxt是dn
int up, dn, nxt[500005], lvl[500005];
void fnd(int x, int pr, int lv) {
/*
找到环最下面的点之后,令 cir[dn]=true
之后只要自己的子节点有 cir=true 的,则自己的 cir=true,如果子节点是up例外
*/
vis[x] = stk[x] = true;
lvl[x] = lv;
for (int i = 0; i < e[x].size(); i++)
if (!vis[e[x][i]]) {
fnd(e[x][i], x, lv + 1);
if (cir[e[x][i]] && e[x][i] != up)
cir[x] = true, nxt[x] = e[x][i];
}
else if (e[x][i] != pr && stk[e[x][i]])
dn = x, up = e[x][i], cir[x] = true, nxt[x] = e[x][i];
stk[x] = false;
}
int main()
{
cin >> n;
for (int i = 1, u, v; i <= n; i++) {
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
return 0;
}
法一:环套树。
把基环树看作一个环上吊了几棵树,在处理时遍历环上每个点,处理出每棵树的答案,然后做环形的操作。
缺点:只能处理基环树,如果是仙人掌就不适用了。
例子:城市环路
法二:树回边。
以深搜树的方式看待,用处理树的方式(比如树形 DP)。在遇到环上深度最浅的结点的时候,让它把下方的环的结果当作一颗子树汇报给父节点。
这样就可以处理仙人掌了。
这种方式把树的结构视为重点,只是多了几条回边。
翻译:求出基环森林中,每颗基环树的直径之和。(带权)
考虑一颗基环树怎么求直径。
先用深搜树找环,记那个环在深搜树中深度最浅/深的结点为
直径分为两类:一类过
对于过
记
于是可以枚举
但是还有一种情况没考虑:若 (虽然不考虑这种情况疑似还有 80)
法一:用类似换根 DP 的方法,单独处理出
法二:仍沿用树形 DP 的思路。
那么
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!