首页 > 其他分享 >CF2050G Tree Destruction 题解

CF2050G Tree Destruction 题解

时间:2024-12-06 21:59:55浏览次数:6  
标签:子树 联通 题解 max1 Tree 个数 CF2050G 节点 dp

【题意简述】

你有一棵树,你可以从里面删除一条链上的节点,问剩下的点的联通块数量最大是多少。

【思路】

一眼树形 dp,默认根为 \(1\)。

我们以这棵树的 \(1\) 节点作为示例。

设 \(dp[i][0]\) 表示 \(i\) 节点的子树中选一条链,\(i\)​ 不在链上的最大联通块数。

设 \(dp[i][1]\) 表示 \(i\) 节点的子树中选一条链,\(i\) 在链端点的最大联通块数。

设 \(dp[i][2]\) 表示 \(i\) 节点的子树中选一条链,\(i\) 在链中间的最大联通块数。

  • \(dp[i][0]\):\(i\) 不在链上,意味着一定是 \(i\) 的某一个子节点的子树内有一条链。

    • \(dp[son][0]\):当前儿子也不在链上,如图所示:

      \(2\) 节点不在红色链上,当前 \(2\) 子树中有一个绿色联通块,发现带上 \(1\) 号点之后联通块扩大,但是个数不变。

    • \(dp[son][1]/dp[son][2]\):当前儿子在链上,如图所示:

      \(2\) 节点在红色链上,当前 \(2\) 子树中有一个绿色联通块,发现带上 \(1\) 号点之后联通块个数 +1。

  • \(dp[i][1]\):\(i\) 在链的端点,意味着

    • 这个子树内只有这一个点在链上,答案即为子树个数。

    • \(i\) 的子节点有一个处于其子树中链的端点上,如图所示:

      \(2\) 节点在红色链上,当前 \(2\) 子树中有两个绿色联通块,连接 \(1\) 号点之后联通块个数 +(子节点个数-1)。

  • \(dp[i][1]\):\(i\) 在链的中间,意味着

    • 有两个子节点处于其子树中链的端点上,如图所示:

      \(2,3\) 节点在红色链上,当前 \(2\) 子树中有两个绿色联通块,\(3\) 子树中没用联通块,连接 \(1\) 号点之后联通块个数 +(子节点个数-2)。

      选择联通块个数最大的两个子树连起来就好。

然后就很好写了。

【Code】

#include <bits/stdc++.h>
using namespace std;

vector<int>Edge[200005];
int n,u,v,dp[200005][3];

void DFS(int u,int fa){
	int soncnt=0,max0=0,max1=0,sec1=0,max2=0;
	for(auto v:Edge[u]){
		if(v!=fa){
			DFS(v,u),soncnt++;
			max0=max(max0,dp[v][0]);
			max2=max(max2,dp[v][2]);
			if(dp[v][1]>max1){
				sec1=max1;
				max1=dp[v][1];
			}else if(dp[v][1]>sec1){
				sec1=dp[v][1];
			}
		}
	}
	dp[u][0]=max(max0,max(max1,max2)+1);
	dp[u][1]=max(soncnt,max1+(soncnt-1));
	dp[u][2]=max1+sec1+(soncnt-2);
} 

void Main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) dp[i][0]=dp[i][1]=dp[i][2]=0,Edge[i].clear();
	for(int i=1;i<=n-1;i++){
		scanf("%d%d",&u,&v);
		Edge[u].push_back(v);
		Edge[v].push_back(u);
	}
	DFS(1,0);
	printf("%d\n",max({dp[1][0],dp[1][1],dp[1][2]})); 
} 

int T;
int main()
{
	scanf("%d",&T);
	while(T--) Main();
	return 0;
}

【后记】

祝贺我自己,在上蓝前的最后一场 Div.3 AK。

两发罚时全是数组开小,乐。

以后就打不了了。

标签:子树,联通,题解,max1,Tree,个数,CF2050G,节点,dp
From: https://www.cnblogs.com/Sundar-2022/p/18591492

相关文章

  • CF2050F Maximum modulo equality 题解
    【题意简述】你有一个长度为\(n\)的数组\(a\)。每一次询问给定\(l,r\),寻找最大的\(m\)使得\(a_l\)到\(a_r\)的所有数对\(m\)同余,【前置数学芝士】首先是一个非常Naive的结论,请自行感性证明:设\(a>b\),\(a\)和\(b\)对\(a-b\)同余。理性证明:设\(p=a-b\),\(......
  • P5007 DDOSvoid 的疑惑 题解
    题目传送门思路树形dp模版题。设\(dp_i\)为\(pos\)的最优解,\(dp2_i\)为只考虑\(pos\)子树时,毒瘤集的数量。可得:\(dp_i=dp_{i}\timesdp2_{son}+dp_{son}\timesdp2_{i}+dp_i+dp_{son}\)\(dp2_i=dp2_{i}\timesdp2_{son}+dp2_{i}+dp2_{son}\)用深搜来更新\(dp\)......
  • 题解:P1007 独木桥
    独木桥-洛谷https://www.luogu.com.cn/problem/P1007思路:输入部分:首先读取独木桥的长度 L 和初始留在桥上的士兵数目 N。然后通过循环读取每个士兵的初始坐标并存储在 soldiers 数组中。计算最小时间和最大时间:对于每个士兵,通过 min(soldiers[i],L+1-soldie......
  • HashMap Knn和KDtree KNN
    chatgpt3的回答使用HashMap进行KNN(K最近邻算法)和使用KD树进行KNN的主要区别在于数据存储和查询效率。HashMap可以快速存储和访问数据,但在处理高维数据时可能会出现高维诅咒的问题,因此不适合进行空间搜索。KD树通过将数据划分为超矩形区域来组织数据,可以更有效地执行邻近查询,特别......
  • 递归疑难问题解答
    1.计算一个数的每位之和(递归实现)写一个递归函数DigitSum(n),输入一个非负整数,返回组成它的数字之和例如,调用DigitSum(1729),则应该返回1+7+2+9,它的和是19输入:1729,输出:19#include<stdio.h>intfac(intn){ if(n<10) { returnn; } else { returnfac(n/10)+......
  • 题解:P3891 [GDOI2014] 采集资源
    P3891[GDOI2014]采集资源题意简述:开始时你有数量为\(m\)的资源,有\(n\)种“苦工”可以不限次数地建造,每种苦工都有一个花费\(a\),和一个效率\(b\),要求最小化资源数量到达\(t\)的时间Solution:我们考虑先对于每一种花费\(i\)最大化它的“单位时间内产生的资源的数量......
  • MQ消息乱序问题解析与实战解决方案
    1.背景在分布式系统中,消息队列(MQ)是实现系统解耦、异步通信的重要工具。然而,MQ消费时出现的消息乱序问题,经常会对业务逻辑的正确执行和系统稳定性产生不良影响。本文将详细探讨MQ消息乱序问题的根源,并提供一系列在实际应用中可行的解决方案。2.MQ消息乱序问题分析常见的MQ消息......
  • P7206 [COCI2019-2020#3] Lampice 题解
    显然可以对答案奇偶分别二分,判断用点分治。考虑对每个点记录到当前分治中心的路径正着和倒着的hash值,那么两个点之间的路径是回文路径可以用一个简单的式子表示,移项一下把跟一个点有关的值放到一边,用unordered_map记录/查询即可,需要卡常,时间复杂度\(\mathcalO(n\log^2n)\)。......
  • CCF-CSP真题 《201412_2_Z字形扫描》Python思路题解
    题目描述:在图像编码的算法中,需要将一个给定的方形矩阵进行 Z 字形扫描(ZigzagScan)。给定一个 n×n的矩阵,Z字形扫描的过程如下图所示:对于下面的 4×4 的矩阵,1539375694647313对其进行 Z 字形扫描后得到长度为 16 的序列:1539739547......
  • 2023年12月GESPC++二级真题解析
    一、单选题(每题2分,共30分)题目123456789101112131415答案CADDDADCDBCDCBB1.以下不可以做为C++变量的是()。A.FiveStarB.fiveStarC.5StarD.Star5【答案】C【考纲知识点】变量的定义与使用(二级考纲知识点范畴),具体涉及到变量名的命名规则。在C++语言中,变量名有严格......