Codeforces Global Round 26 E. Shuffle 【换根DP】

news2024/12/27 4:19:33

E. Shuffle

1

题意

给定一颗 n n n 个节点的树 T T T,现在要求恰好执行下面的程序操作一次

  1. T T T 中选择一个点,作为 T 2 T_2 T2 的新根节点
  2. 将这个点从 T T T 中删除,现在 T T T 被分成了一个或一个以上的连通块树
  3. 对每一个连通块重复上述的操作,并将这个新的点连接到上一个步骤添加到 T 2 T_2 T2 的点

即上述操作是一个递归的过程。

现在要回答经过一次上次的程序后,生成的 T 2 T_2 T2 最多有多少个叶节点

思路

首先我们需要指出结论:除去 T 2 T_2 T2 的根节点,我们能拥有的最大叶子数量就是各个连通块的最大独立集,如果根节点度数为一,我们需要特判并给答案额外加一

这是因为:在我们选择第一个点作为 T 2 T_2 T2 的根节点后,剩下的每一对相邻的点都不可能同时成为叶子,因为它们必定存在一个先后顺序,那么先被选择的那个一定会成为后被选择的那个点的祖先。
那么我们可以得出结论(必要条件):最后的叶子集合一定是一个独立集(点集内部没有边)

假设我们已经有了一个独立集作为最终的目标叶子集合,我们如何保证它们一定是 T 2 T_2 T2 的叶子呢?
我们可以每一步都选择不在 M I S MIS MIS (maximum independent set) 中的点,让它们连接到 T 2 T_2 T2 上,那么最后一定会只剩下我们的叶子集合,即我们的 M I S MIS MIS,它们连接到 T 2 T_2 T2 上自然就是叶子了。
那么到了这里,答案很显然就是最大独立集的大小了,最后特判一下根节点的度数

问题是,我们第一步选择的 T 2 T_2 T2 的根节点是不固定的,我们可以考虑在 T T T 上做 d f s dfs dfs 换根 D P DP DP,通过枚举当前点 u u u 作为根节点,并统计答案

除了当前节点 u u u 外,它将 T T T 分割成了若干个连通子树,那么这些子树内的最大独立集我们可以用类似 树形 D P DP DP 模板题 ”没有上司的舞会“ 的处理方式,以 d p [ u ] [ 0 ] dp[u][0] dp[u][0] 表示 u u u 的子树中,不选 u u u 的最多能选择的点, d p [ u ] [ 1 ] dp[u][1] dp[u][1] 表示选了 u u u,按照独立集的定义,如果 u u u 被选了,那么他的邻居都不能被选

问题在于,如何换根,在线统计当前节点 u u u 的祖先节点的信息?

注意到其实 u u u 的祖先节点也可以看成一颗连通树,我们以 s [ 0 ] s[0] s[0] s [ 1 ] s[1] s[1] 分别表示不选 u u u 的祖先和选了 u u u 的祖先的最大独立集大小。

那么从 u u u 转移到它的儿子 v v v 时, s s s 的变化是: s [ 0 ] = max ⁡ { s 0 , s 1 } + ∑ e ≠ v ∧ e ∈ s o n { u } max ⁡ { d p e , 0 , d p e , 1 } s[0] = \max \{ s_0, s_1 \} + \sum_{e \neq v \wedge e \in son \{u \}} \max \{dp_{e, 0}, dp_{e, 1} \} s[0]=max{s0,s1}+e=veson{u}max{dpe,0,dpe,1}
意思就是:转移到 v v v 时,父亲变为了 u u u,那么 u u u 不选的话, u u u其他儿子可以选或不选(取 max ⁡ \max max), u u u 原本的父亲也可以选或不选

同理, s [ 1 ] = 1 + s 0 + ∑ e ≠ v ∧ e ∈ s o n { u } d p e , 0 s[1] = 1 + s_0 + \sum_{e \neq v \wedge e \in son \{u \}} dp_{e, 0} s[1]=1+s0+e=veson{u}dpe,0
表示选了 u u u,并且其他邻居都不能选。

时间复杂度: O ( n ) O(n) O(n)

#include<bits/stdc++.h>
#define fore(i,l,r)	for(int i=(int)(l);i<(int)(r);++i)
#define fi first
#define se second
#define endl '\n'
#define ull unsigned long long
#define ALL(v) v.begin(), v.end()
#define Debug(x, ed) std::cerr << #x << " = " << x << ed;

const int INF=0x3f3f3f3f;
const long long INFLL=1e18;

typedef long long ll;

const int N = 200005;

std::vector<int> g[N];
int dp[N][2];
int sum_mx[N];
int sum0[N];
int ans;

void dfs0(int u, int fa){
    dp[u][1] = 1;
    dp[u][0] = 0;
    sum_mx[u] = sum0[u] = 0;
    for(auto v : g[u])
        if(v != fa){
            dfs0(v, u);
            sum_mx[u] += std::max(dp[v][0], dp[v][1]);
            sum0[u] += dp[v][0];
            dp[u][0] += std::max(dp[v][0], dp[v][1]);
            dp[u][1] += dp[v][0];
        }
}

void dfs1(int u, int fa, std::array<int, 2> s){
    ans = std::max(ans, sum_mx[u] + std::max(s[0], s[1]) + (g[u].size() == 1));
    for(auto v : g[u])
        if(v != fa){
            std::array<int, 2> a;
            a[0] = std::max(s[0], s[1]) + sum_mx[u] - std::max(dp[v][0], dp[v][1]);
            a[1] = 1 + s[0] + sum0[u] - dp[v][0];
            dfs1(v, u, a);
        }
}

int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int t;
    std::cin >> t;
    while(t--){
        int n;
        std::cin >> n;
        fore(i, 1, n){
            int u, v;
            std::cin >> u >> v;
            g[u].push_back(v);
            g[v].push_back(u);
        }

        dfs0(1, 0);
        ans = 0;
        dfs1(1, 0, {0, 0});

        std::cout << ans << endl;

        fore(i, 1, n + 1) g[i].clear();
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1818535.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux so文件无法找到及某条命令找不到的解决办法

前言 在一些定制软件中可能会自带so文件。或者自带一些二进制命令。 这时会如果运行某个程序会发生 **.so 文件无法找到的错误。 以及 * 某条命令无法找到的错误。 比如像是下面这样 解决办法&#xff1a; so文件无法找到 通过往 LD_LIBRARY_PATH 变量中追加路径来告诉程序…

微软新一代文本转语音模型——笑声,情绪,心情,打造真实AI语音

文本转语音一直是音频领域大家研究的对象&#xff0c;而基于人工智能模型打造的文本转语音的音频总是有机器人的味道&#xff0c;缺乏了人类的感情。如何把人类的感情融入到文本转音频领域一直是各大模型厂家研究的重点。 而OpenAI发布的GPT-4o&#xff08;“o”代表“omni”&a…

老杨说运维 | 基于数据驱动的智观能力建设(文末附现场视频)

本期回顾来自擎创科技创始人兼CEO杨辰的现场演讲 青城山脚下的滔滔江水奔涌而过&#xff0c;承载着擎创一往无前的势头&#xff0c;共同去向未来。2024年6月&#xff0c;双态IT成都用户大会擎创科技“数智化可观测赋能双态运维”专场迎来了完满的收尾。 “没有2200年前李冰率众…

有一个主域名跟多个二级子域名时该怎么申请SSL证书?

当您拥有主域名以及多个子域名时&#xff0c;选择合适的SSL证书类型对于确保网站的安全性至关重要。以下是三种SSL证书类型的简要介绍&#xff1a; 单域名SSL证书&#xff1a; 功能&#xff1a;只能绑定单个域名&#xff0c;无论是主域名还是子域名。 适用场景&#xff1a;仅…

强化学习-tutorial

强化学习 当你发现收集有标注的数据困难&#xff0c;正确答案人类也不知道是什么的时候&#xff0c;往往是考虑使用RL的时候。尽管机器不知道答案是什么&#xff0c;但是机器会知道什么好&#xff0c;什么不好&#xff0c;通过与环境互动获得奖励。 过程 演算法解RL问题&…

二分+ST表+递推,Cf 1237D - Balanced Playlist

一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 Problem - 1237D - Codeforces 二、解题报告 1、思路分析 case3提示我们一件事情&#xff1a;如果存在某个位置永远不停止&#xff0c;那么所有位置都满足永远不停止 很容易证明 随着下标右移&#xff0c…

一键铺货、多商户入驻:了解迅狐多语言跨境商城源码的商业优势

迅狐多语言跨境商城源码是一款创新的电商平台解决方案&#xff0c;具有独特的商业优势。其中&#xff0c;一键铺货和多商户入驻是其核心功能之一&#xff0c;为商家提供了便利和灵活性。 一、一键铺货&#xff1a;简化产品上架流程 对于电商卖家来说&#xff0c;上架商品是一…

LSS 和 BEVDepth算法解读

前言 当前BEV的研究大都基于深度学习的方法&#xff0c;从组织BEV特征信息的方式来看&#xff0c;主流方法分属两类&#xff1a;自底向上方法和自顶向下方法。 自底向上方法比较早的代表工作是LSS&#xff0c;后来BEVDet、BEVDepth等也是基于LSS的框架来进行优化。自底向上方…

qt dll编写和调用

dll编写 新建项目 头文件 #ifndef LIB1_H #define LIB1_H#include "lib1_global.h"class LIB1_EXPORT Lib1 { public:Lib1(); };//要导出的函数&#xff0c;使用extern "C"&#xff0c;否则名称改变将找不到函数extern "C" LIB1_EXPORT int ad…

汽车传动系统为汽车动力总成重要组成部分 我国市场参与者数量不断增长

汽车传动系统为汽车动力总成重要组成部分 我国市场参与者数量不断增长 汽车系统主要包括动力系统、制动系统、传动系统、转向系统、行驶系统、燃油供给系统、照明系统以及电器系统。汽车传动系统指能够将发动机产生的动力转化为车辆行驶驱动力的动力传递装置。汽车传动系统为汽…

什么是电表无人抄表?

1.电表无人抄表&#xff1a;智能时代的新式计量方法 随着科技的发展的迅猛发展&#xff0c;传统电表抄表方法正被一种全新的、高效率的方式所替代——电表无人抄表。这类技术的普及&#xff0c;不仅提升了电力行业的经营效率&#xff0c;同时也为用户增添了更贴心的服务。 2.…

Python邮箱发送如何设置?Python发信方法?

Python邮箱发送邮件需要哪些库&#xff1f;怎么使用Python发信&#xff1f; Python的强大之处在于其丰富的库和模块&#xff0c;使得开发者可以轻松地实现各种功能&#xff0c;包括通过电子邮件发送信息。AokSend将介绍如何在Python中设置和发送电子邮件&#xff0c;以及相关的…

多功能电能表抄表

1.多功能电能表抄表&#xff1a;简述 多功能电能表抄表是一种现代化电力计量方法&#xff0c;它不仅能够纪录电力耗费&#xff0c;还能提供多种多样额外功能&#xff0c;如实时检测、故障预警、远程操作等。相对于传统电度表&#xff0c;它大大提高了电力管理的效率和精确性。…

浅谈网络通信(2)

文章目录 一、TCP1.1、TCP提供的api —— ServerSocket 、Socket1.2、使用TCP协议编写回显服务器1.3、长/短连接 二、应用层协议、传输层协议详解2.1、应用层(后端开发必知必会)2.1.1、自定义应用层协议2.1.2、通用的协议格式2.1.2.1、XML2.1.2.2、json2.1.2.3、protobuffer 2.…

kotlin类型检测与类型转换

一、is与!is操作符 1、使用 is 操作符或其否定形式 !is 在运行时检测对象是否符合给定类型。 fun main() {var a "1"if(a is String) {println("a是字符串类型:${a.length}")}// 或val b a is Stringprintln(b) } 二、"不安全的"转换操作符…

ARM32开发--IIC原理

知不足而奋进 望远山而前行 目录 文章目录 前言 目标 内容 I2C通讯规则 I2C写操作 I2C读流程 通讯信号 开始 结束 发送数据 bit发送 Byte发送 等待响应 接收数据 bit接收 Byte接收 发送响应 总结 前言 在现代消费电子和工业电子领域&#xff0c;各种类型的…

如何察觉自己或者家人是否出现了听力问题?

如何察觉自己或者家人是否出现了听力问题呢&#xff1f;可以从以下两个方面观察&#xff1a; 一&#xff0e;社交方面 • 是不是经常需要别人重复刚说的话才能理解&#xff1f; • 多人对话中是否感到吃力&#xff1f; • 觉得别人讲话含糊不清&#xff1f; • 在人多嘈杂…

YASKAWA机器人HW1171921-B电缆维修

安川机器人作为现代工业自动化的重要设备&#xff0c;其稳定运行对于生产线的连续性和效率至关重要。然而&#xff0c;随着使用时间的增长&#xff0c;可能会出现各种YASKAWA机器人本体线缆故障&#xff0c;如断线、短路、接触不良等。 一、安川工业机器人电缆维修前的准备 在进…

【Python】已解决报错 TypeError: Missing 1 Required Positional Argument

本文摘要&#xff1a;【Python】使用 Python 中将字符串转换为数组&#xff0c;并总结提出了几种可用方案。 &#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博…

谁才是产品界的真正王者?AI产品经理对决普通产品经理!

不同类型的产品经理可能有着不同的工作内容&#xff0c;那么&#xff0c;AI产品经理和普通产品经理之间的工作内容、工作职责、技能要求等方面&#xff0c;存在着哪些具体差异&#xff1f;这篇文章里&#xff0c;作者就进行了总结和梳理&#xff0c;一起来看看吧。 一、工作内容…