考虑最后这棵二叉树的结构,不难发现被移动的点在原树或新树中构成的都是若干棵完整的子树

(若$x$被移动,则$x$在原树或新树的子树中所有点都会被移动)

先在原树中考虑此问题,对于每一棵由被移动的点所构成的极大的子树,将子树大小累加到这棵子树根的父亲的权值$a_{i}$上(初始为0),将深度和累加到答案上(深度定义为到这棵子树根的距离+1)

类似地,对新树也执行此操作,得到权值$b_{i}$(注意新树中深度的定义应该去掉"+1")

下面,问题即要不断选择$(x,y)\in E$(注意一条边有两种选法),使得$a_{x}$增加1且$a_{y}$减小1,并且最小化操作次数,最终将答案加上这个操作次数

考虑每一条边被使用的次数,不难发现最小操作次数即$\sum_{u=1}^{n}\abs{\sum_{v在u的子树中}(a_{v}-b_{v})}$

对于$a_{i}$和$b_{i}$的选择,即令$f_{i,j}$表示以$i$为根的子树中,强制$i$不被移动且$\sum_{v在i的子树中}(b_{v}-a_{v})=j$的最小答案(仅考虑子树内的贡献),下面来考虑转移——

儿子分为被移动和未被移动的,都可以用背包处理,且还需要求出第2类的数量(不超过2),然后再枚举$b_{i}$并将对应的代价加入其中(显然是完全二叉树)

由于$\sum_{v在i的子树中}(b_{v}-a_{v})$并不保证是$\le sz_{v}$的,因此背包的复杂度为$o(n^{2})$

总复杂度即$o(tn^{3})$,可以通过

 1 #include<bits/stdc++.h>
2 using namespace std;
3 #define N 105
4 struct Edge{
5 int nex,to;
6 }edge[N<<1];
7 int E,t,n,x,y,sum[N],head[N],sz[N],tot[N],g[N][3],gg[N][3],f[N][N];
8 void add(int x,int y){
9 edge[E].nex=head[x];
10 edge[E].to=y;
11 head[x]=E++;
12 }
13 void dfs(int k,int fa){
14 sz[k]=1,tot[k]=0;
15 for(int i=head[k];i!=-1;i=edge[i].nex)
16 if (edge[i].to!=fa){
17 dfs(edge[i].to,k);
18 sz[k]+=sz[edge[i].to];
19 tot[k]+=tot[edge[i].to];
20 }
21 tot[k]+=sz[k];
22 memset(g,0x3f,sizeof(g));
23 g[0][0]=0;
24 for(int i=head[k];i!=-1;i=edge[i].nex)
25 if (edge[i].to!=fa){
26 memcpy(gg,g,sizeof(g));
27 for(int j=n;j>=0;j--)
28 for(int p=0;p<3;p++)g[j][p]+=tot[edge[i].to];
29 for(int l=0;l<=n;l++)
30 for(int j=l;j<=n;j++)
31 for(int p=1;p<3;p++)g[j][p]=min(g[j][p],gg[j-l][p-1]+f[edge[i].to][l]);
32 }
33 for(int i=0;i<=n;i++){
34 f[k][i+1]=min(min(g[i][0],g[i][1]),g[i][2]);
35 for(int j=1;j<=i;j++){
36 f[k][i+1]=min(f[k][i+1],g[i-j][0]+sum[j>>1]+sum[j+1>>1]);
37 f[k][i+1]=min(f[k][i+1],g[i-j][1]+sum[j]);
38 }
39 }
40 for(int i=0;i<=n;i++)f[k][i]+=abs(i-sz[k]);
41 }
42 int main(){
43 for(int i=1;i<N;i++)sum[i]=sum[i>>1]+sum[i-1>>1]+i-1;
44 scanf("%d",&t);
45 while (t--){
46 scanf("%d",&n);
47 E=0;
48 memset(head,-1,sizeof(head));
49 for(int i=1;i<n;i++){
50 scanf("%d%d",&x,&y);
51 add(x,y);
52 add(y,x);
53 }
54 dfs(1,0);
55 printf("%d\n",f[1][n]);
56 }
57 return 0;
58 }

[hdu7042]二叉树的更多相关文章

  1. [数据结构]——二叉树(Binary Tree)、二叉搜索树(Binary Search Tree)及其衍生算法

    二叉树(Binary Tree)是最简单的树形数据结构,然而却十分精妙.其衍生出各种算法,以致于占据了数据结构的半壁江山.STL中大名顶顶的关联容器--集合(set).映射(map)便是使用二叉树实现 ...

  2. 二叉树的递归实现(java)

    这里演示的二叉树为3层. 递归实现,先构造出一个root节点,先判断左子节点是否为空,为空则构造左子节点,否则进入下一步判断右子节点是否为空,为空则构造右子节点. 利用层数控制迭代次数. 依次递归第二 ...

  3. c 二叉树的使用

    简单的通过一个寻找嫌疑人的小程序 来演示二叉树的使用 #include <stdio.h> #include <stdlib.h> #include <string.h& ...

  4. Java 二叉树遍历右视图-LeetCode199

    题目如下: 题目给出的例子不太好,容易让人误解成不断顺着右节点访问就好了,但是题目意思并不是这样. 换成通俗的意思:按层遍历二叉树,输出每层的最右端结点. 这就明白时一道二叉树层序遍历的问题,用一个队 ...

  5. 数据结构:二叉树 基于list实现(python版)

    基于python的list实现二叉树 #!/usr/bin/env python # -*- coding:utf-8 -*- class BinTreeValueError(ValueError): ...

  6. [LeetCode] Path Sum III 二叉树的路径和之三

    You are given a binary tree in which each node contains an integer value. Find the number of paths t ...

  7. [LeetCode] Find Leaves of Binary Tree 找二叉树的叶节点

    Given a binary tree, find all leaves and then remove those leaves. Then repeat the previous steps un ...

  8. [LeetCode] Verify Preorder Serialization of a Binary Tree 验证二叉树的先序序列化

    One way to serialize a binary tree is to use pre-oder traversal. When we encounter a non-null node, ...

  9. [LeetCode] Binary Tree Vertical Order Traversal 二叉树的竖直遍历

    Given a binary tree, return the vertical order traversal of its nodes' values. (ie, from top to bott ...

随机推荐

  1. Visual Studio Docker调试端口设置

    一.前言 在Visual Studio 调试程序时,Docker中的容器端口和主机端口映射随机生成,导致每次调试都需要修改前端API接口的地址 二.解决方案 1.修改Docker调试启动参数,找到启动 ...

  2. Server Tools(服务器工具)

    服务器工具 1.发布 # Process: MXD 转 Web 地图 arcpy.MXDToWebMap_server("", "", "" ...

  3. Java基础之(三):IDEA的安装及破解

    IDEA的安装 IDEA官网:IDEA 点击IJ 找好操作系统,点击下载 双击打开,自己找个安装路径 勾选这两个即可 旗舰版破解及汉化 上面是个人社区版,是免费的,但是如果想要使用汉化版的,需要寻找插 ...

  4. NOI 2021 部分题目题解

    最近几天复盘了一下NOI 2021,愈发发觉自己的愚蠢,可惜D2T3仍是不会,于是只写前面的题解 Day1 T1 可以发现,每次相当于将 \(x\to y\) 染上一种全新颜色,然后一条边是重边当且仅 ...

  5. 洛谷3233 HNOI2014(虚树+dp)

    膜拜一发\(mts\_246,forever\_shi\) 这两位爷是真的无敌! 首先来看这个题,一看题目的数据范围和"关键点"字眼,我们就能得知这是一道虚树题 那就先一如既往的建 ...

  6. Vue2源码解读 - 响应式原理及简单实现

    直接进入主题了,想必大家都知道实现vue响应式核心方法就是 Object.defineProperty,那就从它开始说 Object.defineProperty 缺点: 深度监听,需要递归到底,一次 ...

  7. Github Actions 实践

    Github Actions 实践 Github Actions 是 Github 的持续集成服务,通过在 repo 发生特定的行为时执行指定的命令实现自动测试.自动部署等功能. 基本术语 workf ...

  8. CF375D Tree and Queries 题解

    感觉CF的题目名都好朴素的样子 你谷链接 首先这题显然是个dsu on tree 但是我不会. 其次这题显然是个莫队.这我会啊! 然后会发现好像不是很对劲.因为每次询问都有一个k,貌似和传统的莫队数颜 ...

  9. 零基础入门非常好的C语言基础资料

    C语言程序的结构认识 用一个简单的c程序例子,介绍c语言的基本构成.格式.以及良好的书写风格,使小伙伴对c语言有个初步认识. 例1:计算两个整数之和的c程序: #include main() { in ...

  10. Spring Security 的注册登录流程

    Spring Security 的注册登录流程 数据库字段设计 主要数据库字段要有: 用户的 ID 用户名称 联系电话 登录密码(非明文) UserDTO对象 需要一个数据传输对象来将所有注册信息发送 ...