首页 > 其他分享 >基环树

基环树

时间:2024-04-02 20:56:08浏览次数:20  
标签:int ins 基环树 edge Maxn dp

1 基环树概念

1.1 定义

首先,基环树并不是一颗严格的树。它是一张由 \(n\) 个节点,\(n\) 条边组成的图。

1.2 无向联通图上的基环树

首先,一棵树有 \(n\) 个节点,\(n-1\) 条边。那么基环树就可以看做是在一棵树上加了一条边,这样多出了一个环(因此基环树也被称作环套树)。

如下图所示:

934609502a934666bdfc4a11abfae0e9 (557×557) (byteimg.com)

1.3 有向联通图上的基环树

有向图上根据边的方向再次分为两类

1.3.1 内向树

每个节点的出度为 \(1\),如下图:

9d4000e0e95941eea34408758e66ebc9 (557×557) (byteimg.com)

1.3.2 外向树

每个节点的入度为 \(1\),如下图:

e52f6a1cfbdda98626d97e951219a15d.png (557×557) (bdstatic.com)

1.4 非联通图上的基环树

如果整个图非联通,那么又会形成基环树森林、基环外向树森林、基环内向树森林。

2 基环树处理方式

上面的定义其实对于做题没有什么帮助,同时基环树的题目通常也要结合树形或环形 dp 求解。下面介绍一些基本处理方式。

2.1 找环

最基本的一步:先找出基环树中环在哪里。

以无向连通图为例,代码很好想也很好实现:

void dfs(int u, int fa) {
	if(ins[u]) {//在栈内,说明又走回来了
		int v;
		mark[u] = 1;
		while(s[top] != u) {//这些节点均为环上的点
			mark[s[top]] = 1;
			top--;
		}
		return ;
	}
	if(vis[u] == 1) return ;//已经访问(访问并不等价于在栈中)
	s[++top] = u;
	vis[u] = ins[u] = 1;
	for(int i = head[u]; i; i = edge[i].nxt) {
		int to = edge[i].to;
		if(to == fa) continue;
		dfs(to, x);
	}
	top--;
	ins[u] = false;//弹出栈
	return;
}

2.2 树形 dp 处理

由于基环树与普通的树十分接近,因此可以考虑去掉环上的一条边,使整张图变为一颗树之后再开始 dp。

又因为我们删去了一条边,所以会有两个点的关系被删除,所以这种方法一般要 dp 两次。

2.3 环形 dp 处理

首先我们将环拎出来,这样就可以看成是一些树挂在这个环上。我们将所有子树的信息算出来之后合并到环上的节点,这样就可以环形 dp 求解了。

3 例题

对于基环树,概念是没有什么用的,所以直接看一道例题。

3.1 [ZJOI2018] 骑士

首先这道题和 没有上司的舞会 很像,只是变成了基环树。

我们考虑树形 dp 处理,先求出环上的一条边,以这条边上的两点作树形 dp,分别得到 \(f(x,0)\) 和 \(g(y,0)\)。

由于两者只能取一,所以在两个答案中取 \(\max\) 即可。

剩下的注意细节。

#include <bits/stdc++.h>
#define int long long

using namespace std;

typedef long long LL;
const int Maxn = 2e6 + 5;

int n, w[Maxn];

int head[Maxn], edgenum = 1;
struct node {
	int nxt, to;
}edge[Maxn];

void add(int from, int to) {
	edge[++edgenum] = {head[from], to};
	head[from] = edgenum;
}

int st, ed, num;
int vis[Maxn], ins[Maxn];

void fcir(int x, int fa) {
	if(vis[x]) return ;
	vis[x] = ins[x] = 1;
	for(int i = head[x]; i; i = edge[i].nxt) {
		int to = edge[i].to;
		if(to == fa) continue;
		if(ins[to]) {
			st = x, ed = to, num = i;
			continue;
		}
		fcir(to, x);
	}
	ins[x] = 0;
}

int dp[Maxn][2];

void dfs(int x, int fa) {
	dp[x][0] = 0;
	dp[x][1] = w[x];
	for(int i = head[x]; i; i = edge[i].nxt) {
		int to = edge[i].to;
		if(to == fa) continue;
		if(i == num || (i ^ 1) == num)  {
			continue;
		}
		dfs(to, x);
		dp[x][0] += max(dp[to][0], dp[to][1]);
		dp[x][1] += dp[to][0];
	}
}

signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	cin >> n;
	for(int i = 1; i <= n; i++) {
		int v;
		cin >> w[i] >> v;
		add(i, v), add(v, i);
	}
	int ans = 0;
	for(int i = 1; i <= n; i++) {
		if(vis[i]) continue;
		fcir(i, 0);
		dfs(st, 0);
		int ans1 = dp[st][0];
		memset(dp, 0, sizeof dp);
		dfs(ed, 0);
		ans += max(ans1, dp[ed][0]);
	}
	cout << ans ;
	return 0;
}

标签:int,ins,基环树,edge,Maxn,dp
From: https://www.cnblogs.com/dzbblog/p/18111476

相关文章

  • 基环树学习笔记
    基环树学习笔记定义基环树指的是一张有\(n\)个节点和\(n\)条边的图,如果不保证连通的话,那么整张图是一张基环树森林。并且如果将环上的任意一条边去除,那么整棵基环树会成为一棵普通的树。分类基环树有以下几种特殊情况,也是题目中较多出现的。基环内向树指的是在一棵有向......
  • 基环树学习笔记
    1.定义基环树,又称环套树,n个点n条边,也就是一棵树多一条边,形成唯一的环,这是保证这n个点n条边构成的是一个连通图的时候才是唯一环,如果图不连通但是每个连通块点数都等于边数的时候这个图就是一个基环树森林,可以有多个环如果一张有向弱连通图每个点的入度都为1,则称它是一棵基环外......
  • 【图论】基环树 学习笔记
    基环树下面几个条件互相等价:一个图(连通块)是基环树联通块有n个点n条边图上存在且仅存在一个环,且环上每个节点是一颗子树的根。通常情况下树指的都是无向图,但是有向图也可以构成基环树。内向基环树:每个点都有一条出边。容易发现沿着这条边一定会走到环上“向内走”。外......
  • 基环树处理方法
    法一:环套树。把基环树看作一个环上吊了几棵树,在处理时遍历环上每个点,处理出每棵树的答案,然后做环形的操作。缺点:只能处理基环树,如果是仙人掌就不适用了。法二:树回边。以深搜树的方式看待,用处理树的方式(比如树形DP)。在遇到环上深度最浅的结点的时候,让它把下方的环的结果当作一......
  • 基环树
    基环树转载请注明出处,部分内容引自 cly_none 大神的博文。基环树,也是环套树,简单地讲就是在树上再加一条边。它形如一个环,环上每一个点都有一颗子树的形式。因此,对基环树的处理大部分就是对树处理和对环处理。显然,难度在于后者。扣环这是几乎所有基环树处理的第一步。扣环的......
  • 第 365 场周赛 (依赖树, 环形滑动窗口,内向基环树)
    本题可以发现一些枚举的技巧,在枚举多个值的时候,自己有时候脑袋晕晕的,会把变量的更新顺序搞混,此时,可以用依赖树来解决。如同本题:classSolution:defmaximumTripletValue(self,nums:List[int])->int:res=pre_max=pre_dif=0forxinnums:......
  • 基环树学习指南
    基环树学习指南前置芝士一个图中包含n个点n条边,且图中只存在一个环,这样的图被称为基环树(环套树)。基环树比树多了一条边,从而形成了一个环。基环树可以看做以坏点为根的一颗颗子树构成。三大分类基环无向树基环内向树(每个点有且只有一条出边)基环外向树(每一个点只有一条入边)[......
  • 骑士:基环树
    https://www.bilibili.com/video/BV1Aa411Q7qp/?spm_id_from=333.999.0.0&vd_source=23dc8e19d485a6ac47f03f6520fb15c2董老师讲的很清楚https://www.luogu.com.cn/problem/P2607 思路:1、深搜找环2、断环成树,对树深搜计算(断边:标记端点或者标记边)O(N)单向边://LuoguP2......
  • 【基环树 | 题解】P5022 [NOIP2018 提高组] 旅行
    前言一日知基环树弱,固补题。关于基环树基环树定义一个环,环上每个点都有一颗以该点为根的树,如下图为一棵基环树关于基环树常规思路通常来说基环树常规思路是先处理环上树的结果,后通过树的结果来处理换上结果。具体处理方式依照题目来定。然而只是通常来说因为基环树的问......
  • 10.4 国庆 环形dp与基环树笔记
    1.知识点环形dp环形dp的概念•环形dp与基环树在许多环形结构的问题中,我们可以在环中从某个位置把环断开,把这个环变成线性的,然后进行\(dp\)等操作。•把能通过上述操作解决的环形问题称作"可拆解的环形问题"。环形dp的两种策略•第一次在任意位置把环断开成链,按照......