基环树处理方法

无向基环树找环,遍历模板:

#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)。在遇到环上深度最浅的结点的时候,让它把下方的环的结果当作一颗子树汇报给父节点。

这样就可以处理仙人掌了。

这种方式把树的结构视为重点,只是多了几条回边。

Island

翻译:求出基环森林中,每颗基环树的直径之和。(带权)

考虑一颗基环树怎么求直径。

先用深搜树找环,记那个环在深搜树中深度最浅/深的结点为 up/dw,那条回边为 bk,深搜树中结点 x 的带权深度为 lvl[x],一个环上的点 x 在深搜树中在环上的儿子为 cs[x]

直径分为两类:一类过 bk,一类不过 bk。不过 bk 的一类就是树的直径,很简单。

对于过 bk,必然可以看作 bk + up,dw 拓展出去的两条链 的形式。假设 up 在环上走到结点 x 然后离开了环,dwy 离开了环。

xy 之后的命运就已经是树的直径了,在上面已经处理过。唯一不同的就是统计环上的边。upx 的长度是 lvl[x]lvl[up]dwy 的长度是 lvl[dw]lvl[y]

dp1[x]=lvl[x]lvl[up]+x 脱离环后的最长路径,dp2[x]=lvl[dw]lvl[x]+x 脱离环后的最长路径。同时类似前缀和优化,因为环在深搜树上可以看作一条链 + bk,所以额外算一个 mx[x] 表示 max(dp2[x],dp2[cs[x]],dp2[cs[cs[x]]],,dp2[dw])

于是可以枚举 x 的位置,用 bk+dp1[x]+mx[cs[x]] 快速求出 upx 离开环的最大路径长度。

但是还有一种情况没考虑:若 x=up,即 up 直接从原地离开环,并且往祖先方向走。我们的 dp1,dp2,mx 都是以 "子树" 来描述的,不包括往祖先走的情况。(虽然不考虑这种情况疑似还有 80)

法一:用类似换根 DP 的方法,单独处理出 up 向上的长度。但是这违背了我们的初衷:还是把环上的点特殊化了,而且如果要拓展到仙人掌,就要对每个环上最浅的点都做一遍,很麻烦。虽然也是正确的,但是这里不予采用。

法二:仍沿用树形 DP 的思路。up 向上走的路径,负责结点不是 up,而是这条路径上最浅的结点(LCA)up 只需要向上汇报在 up 的 “子树”(包括 bk)中的向下最长路径即可。

那么 up 向下的最长路径是多长呢?如果不过 bk,就是 dp1[up];否则,就是 bk+max(dp2[cs[up]],dp2[cs[cs[up]]],,dp2[dw])=bk+mx[cs[up]],注意这里不包括 dp2[up],否则从 dw 上到 up 路径会和 bk 组成一个环,不再是简单路径。这样就求出了 up 子树的答案,并且对于更多的简单环,这个方法都同样适用。

posted @   FLY_lai  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示