\(\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. Hive的分析函数的使用

    原文: https://www.toutiao.com/i6769120000578945544/?group_id=6769120000578945544 我们先准备数据库.表和数据 开窗分析函数相 ...

  2. 离线下载第三方Python包

    1.进入Python第三方包下载地(https://pypi.org/)搜索自己需要的包 2.下载需要的包的版本 3.将.whl格式的文件更改为.zip文件,并且解压 4.将解压的2个文件放到Pyth ...

  3. IDEA导入Web项目配置Tomcat启动

    1.导入项目 2.配置project 3.导入项目模块 配置Models 4.配置Libraries 5. 6. 7.配置tomcat

  4. mysql数据库优化1

    目录 数据库结构的设计优化 1.数据库结构的设计 2.针对大型的数据量提前进行分库和分表 3.分库分表带来的问题 4.表结构设计注意的问题 查询优化 1.查询语句的注意事项 2.应尽量避免在 wher ...

  5. JavaScript 中BOM的常用操作

    JavaScript BOM操作 1.获取浏览器窗口尺寸 var width=window,innerWidth //获取可视窗口宽度 var height=window.innerHeight // ...

  6. java实现excel表格导入数据库表

    导入excel就是一个上传excel文件,然后获取excel文件数据,然后处理数据并插入到数据库的过程 一.上传excel 前端jsp页面,我的是index.jsp 在页面中我自己加入了一个下载上传文 ...

  7. golang gin框架中使用protocol buffers和JSON两种协议

    首先,我使用protobuf作为IDL,然后提供HTTP POST + JSON BODY的方式来发送请求. 能不能使用HTTTP POST + PB序列化后的二进制BODY呢? 做了一下尝试,非常简 ...

  8. 1000粉!使用Three.js制作一个专属3D奖牌🥇

    背景 破防了 !突然发现 SegmentFault 平台的粉丝数量已经突破 1000 了,它是我的三个博客平台掘金.博客园.SegmentFault中首个粉丝突破 1000 的,于是设计开发这个页面, ...

  9. 计算机视觉3-> yolov5目标检测1 |从入门到出土

    本来就想着是对自己第一次跑yolov5的coco128的一个记录,没想到现在准备总结一下的时候,一方面是继续学习了一些,另一方面是学长的一些任务的要求,挖出了更多的东西,所以把名字改为了"从 ...

  10. Vue.js之计算属性(computed)、属性监听(watch)与方法选项(methods)

    vue.js官网:https://cn.vuejs.org/v2/guide/components-registration.html 一.计算属性-computed 1. 作用:能够避免数据冗余,通 ...