基环树入门

基环树:

是一种有 n 个点 n 条边,且图中只存在一个环的图被称为基环树(环套树)
分三类:

  • 无向树

  • 外向树(每个点只有一条入边)
    在这里插入图片描述

  • 内向树(每个点只有一条出边)
    在这里插入图片描述

基本思路:
1、深搜找环
2、断坏成树,对树根进行dp

实例: 骑士

思路:
1、对于每颗基环树断开环上任意一条边,对这条边的两个端点分别做一次树形dp,两次答案去max
2、累加每颗基环树的max

树形dp:

Code:

#include<bits/stdc++.h>
#define bug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
const int N = 1e6 + 100;
const int mod = 1e9 + 7;
typedef long long ll;
int n,cnt,r1,r2;
int val[N],head[N];
bool vis[N];
struct Node {
	int to,nxt;
} e[N];
ll dp[N][2],res;
void add(int u,int v) {
	++cnt;
	e[cnt] = {v,head[u]};
	head[u] = cnt;
}
void Find(int u,int rt) {
	vis[u] = 1;
	for(int i=head[u]; i; i=e[i].nxt) {
		int v = e[i].to;
		if(v==rt) {
			r1=v;
			r2=u;
			return;
		}
		if(!vis[v]) Find(v,rt);
	}
}
ll dfs(int u,int rt) {
	dp[u][0] = 0;
	dp[u][1] = val[u];
	for(int i=head[u]; i; i=e[i].nxt) {
		int v = e[i].to;
		if(v==rt) continue;
		dfs(v,rt);
		dp[u][0] += max(dp[v][0],dp[v][1]);
		dp[u][1] += dp[v][0];
	}
	return dp[u][0];
}
int main() {

	scanf("%d",&n);
	for(int i=1; i<=n; i++) {
		int w,u;
		scanf("%d%d",&val[i],&u);
		add(u,i);
	}
	for(int i=1; i<=n; i++) {
		if(!vis[i]) {
			r1=r2=0;
			Find(i,i);
			if(r1) {
				ll t1 = dfs(r1,r1);
				ll t2 = dfs(r2,r2);
				//cout<<t1<<" "<<t2<<endl;
				res += max(t1,t2);
			}
		}
	}
	printf("%lld",res);
	return 0;
}
/*
3
10 2
20 3
30 1
*/

写的不好 仅供参考


资源来源: 董晓算法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值