\(\mathcal{Description}\)

  Link.

  对于非空二叉树 \(T\),定义 \(\operatorname{grow}(T)\) 为所有能通过若干次“替换 \(T\) 的某个叶子为任意非空二叉树”的操作得到的二叉树集合;对于非空二叉树集合 \(\mathscr T\),定义 \(\operatorname{grow}(\mathscr T)=\bigcup_{T\in{\mathscr T}}\operatorname{grow}(T)\)。多次询问,每次给定一个 \(\mathscr T\),询问是否仅有有限个二叉树不在 \(\operatorname{grow}(\mathscr T)\) 中。二叉树判等时区分左右儿子,点无编号。

  设单棵树的结点数为 \(n\),则 \(\sum n\le2\times10^6\)。

  这 tm 才叫简要题意。

\(\mathcal{Solution}\)

  谨以本题解表达去年做题的兔子对题面的赞美

  \(\mathbf{X1}\):我们先来研究一个几乎完备的 \(\operatorname{grow}(\mathscr T)\) 吧,在这样的 \(\mathscr T\) 中,会不会有些树不可起到使 \(\operatorname{grow}(\mathscr T)\) 完备的作用呢?

  \(\mathbf{X2}\):嗯,每片叶子都可以生长出任何二叉树,那么,起到决定性作用的是否叶子们的深度

  \(\mathbf{X1}\):那就先控制深度信息!我发现书上也有在这个思路下衍生的定义。

  定义:二叉树集合 \(\mathscr B_n\) 为高度为 \(n\) 的全体二叉树集的,定义为:

\[\mathscr B_n=\{T~|~h(T)=n\land(~\not\exist T',~h(T')=n\land T\in\operatorname{grow}(T'))\}
\]

  \(\mathbf{X2}\):简而言之,这个 \(\mathscr B_n\) 包含了所有高度为 \(n\) 且不能被其他高度为 \(n\) 的树“生长”出来。很显然,\(\operatorname{grow}(\mathscr B_n)\) 包含了所有高度为 \(n\) 的二叉树

  \(\mathbf{X1}\):继续深入的话……说不定 \(\mathscr B_n\) 里的 \(T\) 也有特殊性质呢。

  \(\mathbf{X2}\):(手玩片刻)呀!这样的 \(T\) 看上去都很“瘦小”,具体地,如果结点 \(u\) 同时拥有左右儿子,那么必然有至少一个儿子是叶子。嗯!这是能够证明的结论。

  证明:记 \(p(T)\) 为真时,\(T\) 满足上述性质,否则则不满足。设 \(h(T)=n\),我们希望证明

\[p(T)\Leftrightarrow T\in\mathscr B_n
\]

  对于 \(p(T)\Rightarrow T\in\mathscr B_n\),取出 \(T\) 中一定存在的自根而下长为 \(n\) 的树链 \(L\),这样的链是单独的一条或者在末尾分叉的两条。我们可以断言,若有 \(h(T')=n,T\in\operatorname{grow}(T')\),则 \(T'\) 必然满足 \(L\sube T'\)。而对于其余叶子,由于它们的父亲都在 \(T'\) 的点集中且不是叶子,所以它们也必然在 \(T'\) 的点集中。最终,发现 \(T=T'\),故命题成立。

  另一边,\(p(T)\Leftarrow T\in\mathscr B_n\),仍使用反证法。对于不满足条件的 \(T\),取出一个左右儿子存在且均不是叶子的结点 \(u\),它必然有一个儿子 \(v\) 满足删去 \(v\) 子树后 \(h(T)=n\)。则可将 \(v\) 子树“逆向生长”为单点 \(v\),此时得到的 \(T'\) 满足 \(h(T)=n\) 且 \(T\in\operatorname{grow}(T')\),所以 \(T\not\in\mathscr B_n\),假设矛盾,原命题成立。

  综上,命题得证。

  \(\mathbf{X1}\):离成功更近一步!把这个强大的结论用于题目本身,是不是说,如果 \(T\in\mathscr T\) 不满足上述条件,就能从 \(\mathscr T\) 中剔除 \(T\) 而不改变 \(\operatorname{grow}(\mathscr T)\) 的完备性?……没错!如果 \(T\) 是这样一棵树,且不存在 \(T'\in\mathscr T\setminus\{T\}\) 使得 \(T\in\operatorname{grow}(T')\),如果存在某棵树只能由 \(T\) 生长出来,我们一定能找到这棵树中一个左右儿子均存在且不是叶子的结点 \(u\),将它的一个儿子替换为单点。那么,这棵树的 \(\operatorname{grow}\) 集合与 \(\operatorname{grow}(\mathscr T)\) 交集为空!

  \(\mathbf{X2}\):接下来就只需要直面问题,尝试判断 \(\operatorname{grow}(\mathscr T)\) 是否几乎完备。我们从一棵“希望与 \(\operatorname{grow}(\mathscr T)\) 匹配的树”的视角出发,设当前结点为 \(u\),如果 \(u\) 子树能够匹配上:

  1. 需要 \(T\in\mathscr T\),\(T\) 在此位置上的结点是叶子,这强于以下所有条件。
  2. \(u\) 只有左儿子,需要一个只有左儿子的 \(T\);
  3. \(u\) 只有右儿子,需要一个只有右儿子的 \(T\);
  4. \(u\) 左儿子是叶子,需要同样情况的 \(T\);
  5. \(u\) 右儿子是叶子,需要同样情况的 \(T\);
  6. \(u\) 左右儿子都是叶子,3. 4. 任意。

我们定义 \(\operatorname{syno}(\mathscr T)\) 是一棵四叉树,它是对 \(\mathscr T\) 的等价概括。我们可以每个 \(T\) 合并入其中,依照 1. 2. 3. 4. 四种情况划分儿子编号。最后,定义 \(f(\operatorname{syno}(\mathscr T),u)\) 该四叉树中 \(u\) 子树的完备性,有

\[f(\operatorname{syno}(\mathscr T),u)=\begin{cases}
\text{False}&u\text{ is not in }\operatorname{syno}(\mathscr T)\\
\text{True}&u\text{ meets condition 0.}\\
\bigwedge_{i=0}^3f(\operatorname{syno}(\mathscr T),\operatorname{son}(u,i))&\text{otherwise}
\end{cases}
\]

最终,\(f(\operatorname{syno}(\mathscr T),\operatorname{root})\) 即为答案。复杂度 \(\mathcal O(\sum|T|)\)!

  \(\mathbf{X1}\):不过我发现一个问题欸,为什么题目描述比题解还长呢

\(\mathcal{Code}\)

/* Clearink */

#include <cstdio>
#include <cassert> #define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
#define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i ) inline char fgc() {
static char buf[1 << 17], *p = buf, *q = buf;
return p == q && ( q = buf + fread( p = buf, 1, 1 << 17, stdin ), p == q )
? EOF : *p++;
} inline int rint() {
int x = 0; char s = fgc();
for ( ; s < '0' || '9' < s; s = fgc() );
for ( ; '0' <= s && s <= '9'; s = fgc() ) x = x * 10 + ( s ^ '0' );
return x;
} const int MAXN = 2e6;
int m; struct BinaryTree {
int node, ch[MAXN + 5][2]; inline void clear() {
rep ( i, 1, node ) ch[i][0] = ch[i][1] = 0;
node = 0;
} inline void read() {
clear(), node = rint();
rep ( i, 1, node ) ch[i][0] = rint(), ch[i][1] = rint();
} inline int type( const int u ) const {
/*
-1: illegal node (not a basic tree).
0: left only.
1: right only.
2: left chain and right leaf.
3: right chain and left leaf.
4: 2&3.
*/
int lc = ch[u][0], rc = ch[u][1];
assert( lc || rc );
if ( !rc ) return 0;
if ( !lc ) return 1;
bool lf = !ch[lc][0] && !ch[lc][1], rf = !ch[rc][0] && !ch[rc][1];
if ( lf && rf ) return 4;
if ( rf ) return 2;
if ( lf ) return 3;
return -1;
} inline bool check( const int u ) {
if ( !u || ( !ch[u][0] && !ch[u][1] ) ) return true;
return ~type( u ) && check( ch[u][0] ) && check( ch[u][1] );
}
} binT; struct SynopsisTree {
int node, ch[MAXN + 5][4];
bool tag[MAXN + 5]; inline void clear() {
rep ( i, 1, node ) {
ch[i][0] = ch[i][1] = ch[i][2] = ch[i][3] = 0,
tag[i] = false;
}
node = 1;
} inline void storage( const BinaryTree& T, int& u, const int v ) {
if ( !v ) return ;
if ( !u ) u = ++node;
if ( tag[u] ) return ;
if ( !T.ch[v][0] && !T.ch[v][1] ) return void( tag[u] = true );
int f = T.type( v );
if ( !f ) storage( T, ch[u][0], T.ch[v][0] );
else if ( f == 1 ) storage( T, ch[u][1], T.ch[v][1] );
else {
if ( f == 2 || f == 4 ) storage( T, ch[u][2], T.ch[v][0] );
if ( f == 3 || f == 4 ) storage( T, ch[u][3], T.ch[v][1] );
}
} inline bool complete( const int u ) {
if ( !u || tag[u] ) return !!u;
return complete( ch[u][0] ) && complete( ch[u][1] )
&& complete( ch[u][2] ) && complete( ch[u][3] );
}
} synT; int main() {
for ( int T = rint(), root = 1; T--; ) {
synT.clear(), m = rint();
rep ( i, 1, m ) {
binT.read();
if ( binT.check( 1 ) ) synT.storage( binT, root, 1 );
}
puts( synT.complete( 1 ) ? "Almost Complete" : "No" );
}
return 0;
}

Solution -「NOI 2020」「洛谷 P6776」超现实树的更多相关文章

  1. 洛谷 P6776 - [NOI2020] 超现实树(找性质,神仙题)

    洛谷题面传送门 nb tea 一道! 首先考虑怎样入手分析这个看似非常不可做的问题.首先题目涉及高度无穷的树,根本枚举不了.不过我们冷静一下就会发现,如果我们记 \(mx=\max\limits_{i ...

  2. 「区间DP」「洛谷P1043」数字游戏

    「洛谷P1043」数字游戏 日后再写 代码 /*#!/bin/sh dir=$GEDIT_CURRENT_DOCUMENT_DIR name=$GEDIT_CURRENT_DOCUMENT_NAME ...

  3. 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)

    To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...

  4. 【BZOJ2830/洛谷3830】随机树(动态规划)

    [BZOJ2830/洛谷3830]随机树(动态规划) 题面 洛谷 题解 先考虑第一问. 第一问的答案显然就是所有情况下所有点的深度的平均数. 考虑新加入的两个点,一定会删去某个叶子,然后新加入两个深度 ...

  5. Solution -「JSOI 2019」「洛谷 P5334」节日庆典

    \(\mathscr{Description}\)   Link.   给定字符串 \(S\),求 \(S\) 的每个前缀的最小表示法起始下标(若有多个,取最小的).   \(|S|\le3\time ...

  6. Solution -「洛谷 P4372」Out of Sorts P

    \(\mathcal{Description}\)   OurOJ & 洛谷 P4372(几乎一致)   设计一个排序算法,设现在对 \(\{a_n\}\) 中 \([l,r]\) 内的元素排 ...

  7. Solution -「POI 2010」「洛谷 P3511」MOS-Bridges

    \(\mathcal{Description}\)   Link.(洛谷上这翻译真的一言难尽呐.   给定一个 \(n\) 个点 \(m\) 条边的无向图,一条边 \((u,v,a,b)\) 表示从 ...

  8. Solution -「APIO 2016」「洛谷 P3643」划艇

    \(\mathcal{Description}\)   Link & 双倍经验.   给定 \(n\) 个区间 \([a_i,b_i)\)(注意原题是闭区间,这里只为方便后文描述),求 \(\ ...

  9. Solution -「SDOI 2018」「洛谷 P4606」战略游戏

    \(\mathcal{Description}\)   Link.   给定一个 \(n\) 个点 \(m\) 条边的无向连通图,\(q\) 次询问,每次给出一个点集 \(s\),求至少在原图中删去多 ...

随机推荐

  1. nuxt写路由接口

    //在server/interface/city.js import Router from 'koa-router'; const router = new Router({ prefix:'/ci ...

  2. react中异步组件以及withRouter的使用

    什么是异步组件?简单来说就是异步加载一个组件,正常情况浏览器加载的是我们打包好的bundle.js文件,那么这个文件是集合了所有js是代码,然而我们首屏加载并不需要一次性加载所有的组件,这会造成性能的 ...

  3. react中label标签的作用

    当我们点击输入内容触发input焦点的时候,就需要使用到label标签里的htmlFor属性来扩大点击的区域 代码如下:

  4. 阿里云服务器ECS Ubuntu16.04 + Seafile 搭建私人网盘 (Seafile Pro)

    原文链接:? 传送门 本文主要讲述 使用 Ubuntu 16.04 云服务器 通过脚本实现对 Seafile Pro 的安装,完成私人网盘的搭建 首先给出 Seafile 专业版的下载地址(Linux ...

  5. hisql orm update表数据更新文档

    更新 HiSql数据更新 HiSql 提供了好几种数据更新的方式下面一一介绍一下 如果你的表中增加了这四个字段 字段 描述 类型 CreateTime 创建时间 DateTime CreateName ...

  6. 通过暗码去打开/关闭usb debug开关

    通过暗码去打开/关闭usb debug开关 通过暗码去打开/关闭usb debug开关1. Description2. Analysis3. Solution4. Summary 1. Descrip ...

  7. ubuntu安装更换阿里云镜像源

    如果使用apt-get安装软件过慢,可以考虑以下步骤 1.备份 sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak 2.编辑 sudo vi ...

  8. 【刷题-PAT】A1095 Cars on Campus (30 分)

    1095 Cars on Campus (30 分) Zhejiang University has 8 campuses and a lot of gates. From each gate we ...

  9. 508. Most Frequent Subtree Sum

    Given the root of a tree, you are asked to find the most frequent subtree sum. The subtree sum of a ...

  10. 使用Xamarin开发移动应用示例——数独游戏(一)项目的创建与调试

    最近项目中需要移动客户端,由于团队基本上使用.Net产品线,所以决定使用Xmarin进行开发,这样技术路线统一,便于后期维护.官网上是这样介绍的" Xamarin 允许你使用 .NET 代码 ...