首页 > 其他分享 >代码源 - 基环树

代码源 - 基环树

时间:2023-08-03 11:44:58浏览次数:46  
标签:std dp2 dp1 int res 代码 cyc 基环树


ZJOI2008 骑士

自己写的时候建的是 \(dls\) 的反图 , 想的是基环树不是要保证每个点的出度为 \(1\) , 就选择每个点向仇恨点连接一条有向边.
这种情况下如果记录每一个点出度指向哪 , 那么在找环的时候不一定能找到 , 因为图上带环的话要根据入度点找环 (画图理解)
如果记录入度指向哪 , 这是这样建图你不能保证每一个点都有入度
所以按 \(dls\) 的方式建边 , 保证每一个点均有入读点(父亲) , 且满足基环树性质 (反过来入度为 1)

#include <bits/stdc++.h>
using ll = long long;

const ll INF = 1E18;

int main() 
{
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	
	int n;
	std::cin >> n;
	
	std::vector<std::vector<int>> g(n);
	std::vector<int> val(n) , p(n);
	
	for (int i = 0 ; i < n ; ++i) {
		std::cin >> val[i] >> p[i];
		p[i]--;
		g[p[i]].push_back(i);
	} 
	
	ll ans = 0;
	std::vector<int> vis(n , 0) , oncyc(n , 0);
	std::vector<std::array<ll,2>> dp1(n , {0 , 0}) , dp2(n);
	
	for (int i = 0 ; i < n ; ++i) {
		
		if (vis[i]) continue;
		//利用基环树出度是 1 的性质 
		int u = i;
		while (!vis[u]) {
			vis[u] = 1 ; u = p[u];
		}
		
		int v = u;
		std::vector<int> cyc;
		while (true) {
			oncyc[v] = 1;
			cyc.push_back(v);
			v = p[v];
			if (u == v) break;
		}
		
		std::function<void(int)> dfs = [&] (int u) {
			dp1[u][1] = val[u] , vis[u] = true;
			for (auto v : g[u]) {
				if (oncyc[v]) continue;
				dfs(v);
				dp1[u][0] += std::max(dp1[v][0] , dp1[v][1]);
				dp1[u][1] += dp1[v][0];
			}
		};
		
		//树形 dp 
		int m = cyc.size();
		for (auto v : cyc) 
			dfs(v);
		
		
		//环形 dp , 拆环为链 , 枚举环上第一个点的状态 
		ll res = 0;
		for (int t = 0 ; t < 2 ; ++t) {
			
			for (int s = 0 ; s < 2 ; ++s) {
				if (s != t) dp2[0][s] = -INF;	
				else dp2[0][s] = dp1[cyc[0]][s];
			}
			
			for (int i = 1 ; i < m ; ++i) {
				int u = cyc[i];
				dp2[i][0] =  dp1[u][0] + std::max(dp2[i - 1][0] , dp2[i - 1][1]);
				dp2[i][1] =  dp1[u][1] + dp2[i - 1][0];
			}
			
			if (t == 0) res = std::max({res , dp2[m - 1][0] , dp2[m - 1][1]});
			else res = std::max(res , dp2[m - 1][0]);
		}
		
		ans += res;
		
	}
	
	std::cout << ans << '\n';
	 
	return 0;	
}

标签:std,dp2,dp1,int,res,代码,cyc,基环树
From: https://www.cnblogs.com/xqy2003/p/17602880.html

相关文章

  • redis远程代码执行CVE-2016-8339
       Redis3.2.x<3.2.4版本存在缓冲区溢出漏洞,可导致任意代码执行。Redis数据结构存储的CONFIGSET命令中client-output-buffer-limit选项处理存在越界写漏洞。构造的CONFIGSET命令可导致越界写,代码执行。漏洞利用:修改配置文件redis.confcpredis.conf./src/......
  • RPA开发复杂流程-为什么使用编码自动化而不是低代码?
    答:编码自动化可以让任何熟悉编码或脚本的人都能体验到更高的生产力、更好的复杂性管理、更高的协作和可审查性、改进的可读性和更高的性能。 ......
  • 【HarmonyOS】性能优化之低代码开发加载多张轮播图
    ​【关键字】HarmonyOS、低代码开发、Swiper组件、性能优化、分页加载 写在前面目前使用DevEco Studio的低代码工具开发元服务时,通过实际测试发现,Swiper组件加载多张轮播图时加载显示耗时较长(实际测试网络状态一般的情况下显示耗时达到8秒以上),根据互联网中的8秒定律,这严重影......
  • 【HarmonyOS】性能优化之低代码开发加载多张轮播图
    【关键字】HarmonyOS、低代码开发、Swiper组件、性能优化、分页加载写在前面目前使用DevEco Studio的低代码工具开发元服务时,通过实际测试发现,Swiper组件加载多张轮播图时加载显示耗时较长(实际测试网络状态一般的情况下显示耗时达到8秒以上),根据互联网中的8秒定律,这严重影响了用户......
  • [代码随想录]Day07-字符串 part01
    题目:344.反转字符串思路:每次把最前面和最后面的交换位置即可strings库里没有反转的方法——这个反转是之后几个题的一个基础代码:双指针调换位置funcreverseString(s[]byte){l,r:=0,len(s)-1//最前面的元素,最后面的元素forl<r{s[l],s[......
  • Android手部检测和手势识别(含训练代码+Android源码+手势识别数据集)
    Android手部检测和手势识别(含训练代码+Android源码+手势识别数据集)目录Android实时手势动作识别(含训练代码++手势识别数据集)1.前言2.手势识别的方法(1)基于多目标检测的手势识别方法(2)基于手部检测+手势分类识别方法3.手势识别数据集说明(1)HaGRID手势识别数据集(2)自定义数据集4.基于......
  • 使用python进行贝叶斯统计分析|附代码数据
    原文链接:http://tecdat.cn/?p=7637最近我们被客户要求撰写关于贝叶斯统计的研究报告,包括一些图形和统计输出。本文讲解了使用PyMC3进行基本的贝叶斯统计分析过程. ( 点击文末“阅读原文”获取完整代码数据******** )。  #Importsimportpymc3aspm#python的概率......
  • 数据分享|R语言ARIMA模型分析预测上海空气质量指数AQI时间序列|附代码数据
    全文链接:http://tecdat.cn/?p=32265原文出处:拓端数据部落公众号最近我们被客户要求撰写关于上海空气质量指数的研究报告,包括一些图形和统计输出。指数平滑法对于预测来说是非常有帮助的,而且它对时间序列上面连续的值之间相关性没有要求。但是,如果你想使用指数平滑法计算出预测......
  • github代码外泄监控——可用来提供源码泄露检测服务,数据泄露场景,原理就是在github搜索
     Hawkeye监控github代码库,及时发现员工托管公司代码到GitHub行为并预警,降低代码泄露风险。特点优点邮箱告警通知黑名单添加爬虫任务设置缺点spider通过关键词在github进行模糊搜索,搜索结果会比较杂依赖Python3.x(Hawkeye支持Python3.xonLinuxandmacOS;2.x兼容性需自行修改测试......
  • 基于蜉蝣优化算法实现聚类附matlab代码
    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。......