较难的换根dp:P6213 「SWTR-04」Collecting Coins
传送门
前题提要:感觉这道换根dp可以说是集中了换根dp的所有较高难度的操作和思想,以及较高的一些实现细节,可以说能够完全写出这道题才叫真正理解了换根dp,非常值得一做.
首先读完题意,不难发现这道题有很多限制.点的访问次数限制,必须访问某一个点,想要获得最大的贡献,没有限制初始起点.乍一看感觉完全没办法解决,我们考虑一个一个的去解决上述限制.
首先假设只想获得最大的贡献,那么这个显然是一个简单的树形dp,也就是 f [ u ] = m a x ( f [ v ] + w ) f[u]=max(f[v]+w) f[u]=max(f[v]+w). f [ u ] f[u] f[u]表示访问 u u u子树所能获得的最大贡献.
然后我们考虑加上访问次数的限制,我们发现对于一个点,无论他是起始点还是中途经过的点,只要访问这个点,我们就损失了一个进入机会.然后显然我们想访问一个子树获得子树的贡献就需要花费一次进入机会,因为我们进入一个子树必然需要返回.诶,此时我们就可以解决了.假设一个点的访问次数限制为 k k k,那么对于这个点来说,我们最多只能加入 k − 1 k-1 k−1个子树的贡献.所以我们考虑对所有子树的贡献进行一个排序,然后取前 k − 1 k-1 k−1个最大的贡献即可.
然后我们再考虑加入必须访问一个点的贡献.这一点直接解决起来就有点困难了,我们需要转化一下这个条件.我们考虑将这个必须访问的点当做我们的遍历的树的根节点,这样我们的必须访问的需求就迎刃而解了.因为对于刚开始的一棵树来说,我们这个根节点是必须遍历的,没有任何问题.
然后因为本题并没有限制初始点,所以我们需要进行一个换根.那么对于换完根的树来说,因为存在一个必须访问的点,所以我们限制换完根的子树必须选祖先那个子树即可.然后在自己的子树里选出前 k − 2 k-2 k−2大的.
至此本题的主要解决思路就结束了,但是本题在换根上的细节和经验问题还是比较多的(反正我当时在写这道题被细节方面搞了很久),接下来详细讲讲细节方面的处理
其实建议不看下文自己解决细节问题,毕竟只有自己的连续思考才毕竟清楚
考虑我们维护出了 f [ u ] f[u] f[u]表示访问一个节点所能获得的最大贡献,并且因为换根需求,我们考虑记录使用 m a x _ f max\_f max_f记录下所有的u子树对u的贡献,并且对此从大到小排个序.
PS:这种记录子树对u的贡献的方法在很多题目中都需要体现(因为换根的时候需要考虑自身节点对父亲的贡献),但是很多题目都是记录最大值和次大值即可,这样较为方便,但是实际上那些题目都是可以直接记录所有的贡献然后等会处理,并且在本题中光记录最大和次大并不能解决问题,所以考虑直接记录所有的贡献
因为我们的父亲节点是必选的,为了方便解决问题,不妨设置一个辅助数组 f a _ v a l [ u ] fa\_val[u] fa_val[u]来记录以 u u u为根时 u u u节点的父亲子树对 u u u的贡献.然后设 d p [ u ] dp[u] dp[u]记录以 u u u为根时的贡献.
先来维护 f a _ v a l [ u ] fa\_val[u] fa_val[u]数组
然后我们考虑根节点从 u − > v u->v u−>v转移,此时需要进行分类讨论,考虑先维护辅助数组:
- 当v子树是 f [ u ] f[u] f[u]数组的一个贡献来源时:此时我们想要维护 f a _ v a l [ u ] fa\_val[u] fa_val[u]时,我们需要花费一次进入机会从 v v v进入到 u u u,然后我们还需要一次进入机会从 u u u到 u u u的父亲节点(因为父亲节点是必选的),所以此时我们就只剩下 k − 2 k-2 k−2棵可选择的子树贡献(并且这个k-2可子树是不能包括v的),那么考虑预处理出原本 u u u子树原 k − 1 k-1 k−1课子树的总贡献,然后减掉 v v v这个子树的贡献就维护出了前 k − 2 k-2 k−2棵除v子树外的最大贡献了.但是光光这样的方式是有问题的(当时卡了我很长时间),因为假设我们的u是根节点时,我们此时没有父亲那边的贡献,并且我们也不需要花一次进入机会去进入到父亲节点,所以这种情况下是需要特判的,具体特判方式看下文代码即可,此处不在赘述
- 考虑v子树不是 f [ u ] f[u] f[u]的一个贡献来源,那么此时我们想要维护 f a _ v a l [ u ] fa\_val[u] fa_val[u]时,我们同样此时只需要记录 u u u子树除 v v v外的前 k − 2 k-2 k−2棵子树的贡献即可.因为此时v不处于前 k − 1 k-1 k−1大的贡献之间,所以我们直接预处理前 k − 2 k-2 k−2的 m a x _ f max\_f max_f的和即可.同样的,当我们是处于根节点时照样需要特判.
考虑我们如果维护出了 f a _ v a l fa\_val fa_val数组之后,对于我们的 d p dp dp数组就不难维护了,我们此时的 d p [ u ] = f a _ v a l [ u ] + u 前 k − 2 大的子树的贡献和 dp[u]=fa\_val[u]+u前k-2大的子树的贡献和 dp[u]=fa_val[u]+u前k−2大的子树的贡献和
PS:此处同时也有一个小trick,因为时间复杂度的约束,我们不能实时的枚举v是否是u的一个贡献子树,所以我们需要在遍历子树之前先预处理一下这个状态,并且同时记录下前k-1大,前k大,前k-2大的子树的贡献和即可
下面是具体的代码部分:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {ll x=0,w=1;char ch=getchar();for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';return x*w;
}
inline void print(__int128 x){if(x<0) {putchar('-');x=-x;}if(x>9) print(x/10);putchar(x%10+'0');
}
#define maxn 1000000
const double eps=1e-8;
#define int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
struct Edge{int v,w;
};
vector<Edge>edge[maxn];int k[maxn];
int f[maxn];vector<pair<int,int> >max_f[maxn];
int n,d;
void dfs1(int u,int per_u) {for(auto [v,w]:edge[u]) {if(v==per_u) continue;dfs1(v,u);max_f[u].push_back({f[v]+w,v});}sort(max_f[u].begin(),max_f[u].end());reverse(max_f[u].begin(),max_f[u].end());for(int i=0;i<min((int)max_f[u].size(),k[u]-1);i++) {f[u]+=max_f[u][i].first;}
}
int dp[maxn];int check[maxn];int fa_val[maxn];
void dfs2(int u,int per_u) {int sum1=0,sum2=0,sum3=0;for(int i=0;i<max_f[u].size();i++) {int v=max_f[u][i].second;int w=max_f[u][i].first;if(i<k[u]-1) sum1+=w,check[v]=1;if(i<k[u]) sum2+=w;if(i<k[u]-2) sum3+=w;}dp[u]+=sum3;for(auto [v,w]:edge[u]) {if(v==per_u) continue;if(k[v]==1) continue;if(check[v]) {if(u!=d) fa_val[v]=fa_val[u]+sum1-f[v]-w+w;else fa_val[v]=fa_val[u]+sum2-f[v]-w+w; dp[v]=fa_val[v];}else {if(u!=d) fa_val[v]=fa_val[u]+sum3+w;else fa_val[v]=fa_val[u]+sum1+w; dp[v]=fa_val[v];} dfs2(v,u);}
}
int main() {n=read();d=read();for(int i=1;i<n;i++) {int u=read();int v=read();int w=read();edge[u].push_back({v,w});edge[v].push_back({u,w});}for(int i=1;i<=n;i++) {k[i]=read();}dfs1(d,0);dfs2(d,0);int ans=f[d];for(int i=1;i<=n;i++) {ans=max(ans,dp[i]);}cout<<ans<<endl;return 0;
}
相关文章:
较难的换根dp:P6213 「SWTR-04」Collecting Coins
传送门 前题提要:感觉这道换根dp可以说是集中了换根dp的所有较高难度的操作和思想,以及较高的一些实现细节,可以说能够完全写出这道题才叫真正理解了换根dp,非常值得一做. 首先读完题意,不难发现这道题有很多限制.点的访问次数限制,必须访问某一个点,想要获得最大的贡献,没有…...
Springboot - 15.二级分布式缓存集成-Caffeine
👀中文文档 Caffeine 👀使用Caffeine (本地缓存) 当与Spring Boot结合使用时,Caffeine提供了一个直观且功能强大的二级缓存解决方案。Spring Boot的缓存抽象使得整合Caffeine变得相当简单。以下是如何在Spring Boot…...

二叉树的介绍及二叉树的链式结构的实现(C语言版)
前言 二叉树是一种特殊的树,它最大的度为2,每个节点至多只有两个子树。它是一种基础的数据结构,后面很多重要的数据结构都是依靠它来进行实现的。了解并且掌握它是很重要的。 目录 1.二叉树的介绍 1.1概念 1.2现实中的二叉树 1.3特殊的二叉…...

不同写法的性能差异
“ 达到相同目的,可以有多种写法,每种写法有性能、可读性方面的区别,本文旨在探讨不同写法之间的性能差异 len(str) vs str "" 本部分参考自: [问个 Go 问题,字符串 len 0 和 字符串 "" ,有啥区别?](https://segmentf…...

Bytebase 2.7.0 - 新增分支(Branching)功能
🚀 新功能 新增支持与 Git 类似的分支(Branching)功能来管理 schema 变更。支持搜索所有历史工单。支持导出审计日志。 🎄 改进 变更数据库工单详情页面全新改版。优化工单搜索体验。SQL 审核规则支持针对不同数据库进行独立配…...
day55 动规.p15 子序列
- 392.判断子序列 cpp class Solution { public: bool isSubsequence(string s, string t) { vector<vector<int>> dp(s.size() 1, vector<int>(t.size() 1, 0)); for (int i 1; i < s.size(); i) { for (int j 1; …...
TypeScript DOM类型的声明
TS DOM类型的声明 lib.dom.d.ts HTMLInputElement <input type"text" change"handleChange" /> const handleChange (evt: Event) > {console.log((evt.target as HTMLInputElement).value); } HTMLElement const div: HTMLDivElement do…...

springboot找不到注册的bean
1、错误描述 A component required a bean named ‘fixedAssetsShareMapper’ that could not be found.Action:Consider defining a bean named ‘fixedAssetsShareMapper’ in your configuration.2、问题分析 1、该错误提示表明在你的应用程序中有一个组件(可能…...

MEMS传感器的原理与构造——单片式硅陀螺仪
一、前言 机械转子式陀螺仪在很长的一段时间内都是唯一的选项,也正是因为它的结构和原理,使其不再适用于现代小型、单体、集成式传感器的设计。常规的机械转子式陀螺仪包括平衡环、支撑轴承、电机和转子等部件,这些部件需要精密加工和…...

Redis集群服务器
集群简介 试想有一家餐厅,如果顾客人数较少,那么餐厅只需要一个服务员即可,如图1。但是,当顾客人数非常多时,一个服务员是绝对不够的,如图2。此时,餐厅需要雇用更多的服务员来解决大量访问&…...

动态维护直径 || 动态维护树上路径 || 涉及LCA点转序列 || 对欧拉环游序用数据结构维护:1192B
https://www.luogu.com.cn/problem/CF1192B 对于直径的求法,常用dp或两次dfs,但如果要动态维护似乎都不太方面,那么可以维护树上路径最大值。 树上路径为: d e p u d e p v − 2 d e p l c a ( u , v ) dep_udep_v-2\times de…...

MySQL 存储引擎,你了解几个?
引言 MySQL是一种流行的关系型数据库管理系统(RDBMS),它支持多种不同的数据库引擎。数据库引擎是用于存储、管理和检索数据的核心组件,它们直接影响着数据库的性能、可靠性和功能,接下来本文介绍下一些常见的MySQL数据…...

Java 动态规划 Leetcode 740. 删除并获得点数
题目 对于该题的题目分析,已经代码分析都一并写入到了代码注释中 代码 class Solution {public int deleteAndEarn(int[] nums) {//核心思路://由于我们获得 nums[i] 的点数之后,就必须删除所有等于 nums[i] - 1 和 nums[i] 1 的元素//假设…...
算法通关村十三关-青铜:数字与数学基础问题
1.数字统计专题 统计特定场景下的符号或数字个数等 1.1符号统计 LeetCode1822 数组元素积的符号 https://leetcode.cn/problems/sign-of-the-product-of-an-array/description/ 思路分析 如果将所有的数都乘起来,再判断正负,工作量大,还…...

猜拳游戏小程序源码 大转盘积分游戏小程序源码 积分游戏小程序源码
简介: 猜拳游戏大转盘积分游戏小程序前端模板源码,一共五个静态页面,首页、任务列表、大转盘和猜拳等五个页面 图片:...

【Python】爬虫练习-爬取豆瓣网电影评论用户的观影习惯数据
目录 前言 一、配置环境 1.1、 安装Python 1.2、 安装Requests库和BeautifulSoup库 1.3.、安装Matplotlib 二、登录豆瓣网(重点) 2.1、获取代理 2.2、测试代理ip是否可用 2.3、设置大量请求头随机使用 2.4、登录豆瓣网 三、爬取某一部热门电影…...
webpack基础配置【总结】
webpack打包原理: webpack是一个js应用程序的静态模块打包工具,当webpack处理应用程序时,它的内部构建一个依赖图,此时依赖会映射项目中所需的每个模块,并生成一个或多个bundle包。因此我们会安装配置各种打包规则&…...

typescript 支持与本地调试
typescript 支持与本地调试 typescript 支持与本地调试 前言支持 typescript函数的本地调试 启用 node-terminal 调试invoke localserverless-offline Next Chapter完整示例及文章仓库地址 前言 在上一章节,我们创建了一个 hello world 函数,并把它顺…...
后端面试话术集锦第 十八 篇:JVM面试话术
这是后端面试集锦第十八篇博文——JVM面试话术❗❗❗ 1. 介绍下JVM JVM主要包括:类加载器(class loader)、执行引擎(exection engine)、本地接口(native interface)、运行时数据区(Runtimedata area) 类加载器:加载类文件到内存。Class loader只管加载,只要符合文件…...

“历久弥新 | 用AI修复亚运珍贵史料”活动震撼来袭!
时隔近半个世纪,新中国第一次参与亚运会的影像资料将首次对外披露。只是年代久远,老照片老视频都有了岁月痕迹,画面不再清晰,这些珍贵史料急需你的帮助! 一、活动介绍 2023年,正值亚运110周年,…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...

Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】
大家好,我是java1234_小锋老师,看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】,分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)
前言: 双亲委派机制对于面试这块来说非常重要,在实际开发中也是经常遇见需要打破双亲委派的需求,今天我们一起来探索一下什么是双亲委派机制,在此之前我们先介绍一下类的加载器。 目录 编辑 前言: 类加载器 1. …...

【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...

高抗扰度汽车光耦合器的特性
晶台光电推出的125℃光耦合器系列产品(包括KL357NU、KL3H7U和KL817U),专为高温环境下的汽车应用设计,具备以下核心优势和技术特点: 一、技术特性分析 高温稳定性 采用先进的LED技术和优化的IC设计,确保在…...
Linux中INADDR_ANY详解
在Linux网络编程中,INADDR_ANY 是一个特殊的IPv4地址常量(定义在 <netinet/in.h> 头文件中),用于表示绑定到所有可用网络接口的地址。它是服务器程序中的常见用法,允许套接字监听所有本地IP地址上的连接请求。 关…...
GB/T 43887-2024 核级柔性石墨板材检测
核级柔性石墨板材是指以可膨胀石墨为原料、未经改性和增强、用于核工业的核级柔性石墨板材。 GB/T 43887-2024核级柔性石墨板材检测检测指标: 测试项目 测试标准 外观 GB/T 43887 尺寸偏差 GB/T 43887 化学成分 GB/T 43887 密度偏差 GB/T 43887 拉伸强度…...