\(noip2018\) \(T4\)题解

  • 其实呢,我是觉得这题比\(T3\)水到不知道哪里去了

  • 毕竟我比较菜,不大会\(dp\)

  • 好了开始讲正事

  • 这题其实考察的其实就是选手对D(大)F(法)S(师)的掌握程度

  • 考完试有人说这题是马拉车,吓死我了

  • 首先,你把数据读入之后,先用一个大法师把以每个节点为根的子树的大小和权值都预处理出来,方便待会剪枝

  • 然后,你对以每个节点为根的子树,都判断一下以下条件(这时刚才处理的东西就有用了)

  • ① 左子树和右子树的节点数是否相等

  • ② 左子树和右子树的权值是否相等

  • ③ 以当前节点为根的子树大小是不是超过答案

  • 第三个很重要,不加(洛谷数据)最后一个点会TLE

  • 有一个显而易见的剪枝:因为答案至少是1,所以大小为1的子树就不用check了,不然浪费常数

  • 然后就是暴力判了

  • 递归下去,建立两个队列,保存当前处理到的左子树上和右子树上的节点,判左子树当前节点的左儿子和右子树当前节点的右儿子权值是否相等,右子树当前节点的左儿子和左子树当前节点的右儿子权值是否相等(注意对应)

  • 还有判下对应的节点有没有一个是空的一个没空的情况

  • 如果不相等就返回

  • 相等的话就扔进队列(注意对应顺序!)

  • 注意:上述处理一定要左右子树一起做,不能先处理一边,再处理另一边,不然会WA

  • 到最后如果都可以的话就return true

  • 附考场代码

  • 不得不说,为了能过,我加了一堆卡常

  • 3e6的输入规模应该还是要快读的吧

# include <bits/stdc++.h>

# define R register

const int MaxN = 1000010;

struct node//节点
{
int val;
int l, r;
}; node a[MaxN];
int f[MaxN], val[MaxN], ind[MaxN];//f[i]表示以i为根的子树大小,val表示以i为根的子树权值和,ind没啥用 inline void read(int &x)//快读
{
x = 0;
bool op = 1;
char ch = getchar();
while(ch > '9' || ch < '0')
{
if(ch == '-')
op = 0;
ch = getchar();
}
while(ch <= '9' && ch >= '0')
x = (x << 1) + (x << 3) + (ch - '0'), ch = getchar();
if(!op)
x = -x;
} void dfs(int root)
{
if(root == -1)
return;
if(a[root].l == -1 && a[root].r == -1)
f[root] = 1, val[root] = a[root].val;
else
{
dfs(a[root].l);
dfs(a[root].r);
f[root] = f[a[root].l] + f[a[root].r] + 1;
val[root] = val[a[root].l] + val[a[root].r] + a[root].val;
} } inline int check(int x)
{
std::queue<int> l, r;
l.push(x), r.push(x);
while(!l.empty() || !r.empty())
{
if(l.empty() || r.empty())
return false;//一边空了,一边没空
R int lx = l.front(), rx = r.front();
l.pop(), r.pop();
if(a[lx].val != a[rx].val)
return false;
R int lson[3], rson[3];
lson[1] = a[lx].l, lson[2] = a[lx].r;//左子树当前节点的左儿子,左子树当前节点的右儿子
rson[1] = a[rx].l, rson[2] = a[rx].r;//右子树当前节点的左儿子,右子树当前节点的右儿子
if((lson[1] == -1 && rson[2] != -1) || (lson[1] != -1 && rson[2] == -1))
return false;//一边空了,一边没空
if((lson[2] == -1 && rson[1] != -1) || (lson[2] != -1 && rson[1] == -1))
return false;//一边空了,一边没空
if(lson[1] != -1)
l.push(lson[1]);
if(lson[2] != -1)
l.push(lson[2]);
if(rson[2] != -1)
r.push(rson[2]);
if(rson[1] != -1)
r.push(rson[1]);
//推进队列
}
return true;
} int main()
{
// freopen("tree.in", "r", stdin);
// freopen("tree.out", "w", stdout);
R int n;
scanf("%d", &n);
for(R unsigned i = 1; i <= n; ++i)
read(a[i].val);
for(R unsigned i = 1; i <= n; ++i)
read(a[i].l), read(a[i].r), ++ind[a[i].l], ++ind[a[i].r];//处理入度
R unsigned root;
for(R unsigned i = 1; i <= n; ++i)
{
if(!ind[i])
{
root = i;
break;
}
}//找树根
dfs(root);//预处理
int ans = 1;
for(R unsigned i = 1; i <= n; ++i)//枚举子树
{
if(f[a[i].l] != f[a[i].r])
continue;//剪枝1
if(val[a[i].l] != val[a[i].r])
continue;//剪枝2
if(f[i] < ans || f[i] == 1)
continue;//剪枝3
if(check(i))
ans = f[i];//更新答案
}
printf("%d", ans);
fclose(stdin);
fclose(stdout);
return 0;
}

题解 洛谷P5018【对称二叉树】(noip2018T4)的更多相关文章

  1. 洛谷P5018 对称二叉树——hash

    给一手链接 https://www.luogu.com.cn/problem/P5018 这道题其实就是用hash水过去的,我们维护两个hash 一个是先左子树后右子树的h1 一个是先右子树后左子树的 ...

  2. 洛谷P5018 对称二叉树

    不多扯题目 直接题解= = 1.递归 由题目可以得知,子树既可以是根节点和叶节点组成,也可以是一个节点,题意中的对称二叉子树是必须由一个根节点一直到树的最底部所组成的树. 这样一来就简单了,我们很容易 ...

  3. NOIP2018普及T4暨洛谷P5018 对称二叉树题解

    题目链接:https://www.luogu.org/problemnew/show/P5018 花絮:这道题真的比历年的t4都简单的多呀,而且本蒟蒻做得出t4做不出t3呜呜呜... 这道题可以是一只 ...

  4. 洛谷 P5018 对称二叉树(搜索)

    嗯... 题目链接:https://www.luogu.org/problem/P5018 其实这道题直接搜索就可以搜满分: 首先递归把每个点作为根节点的儿子的数量初始化出来,然后看这个节点作为根节点 ...

  5. 【洛谷P5018 对称二叉树】

    话说这图也太大了吧 这题十分的简单,我们可以用两个指针指向左右两个对称的东西,然后比较就行了 复杂度O(n*logn) #include<bits/stdc++.h> using name ...

  6. 洛谷 P5018 对称二叉树

    题目传送门 解题思路: 先计算每个点的子树有多少节点,然后判断每个子树是不是对称的,更新答案. AC代码: #include<iostream> #include<cstdio> ...

  7. 2021.08.09 P5018 对称二叉树(树形结构)

    2021.08.09 P5018 对称二叉树(树形结构) [P5018 NOIP2018 普及组] 对称二叉树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题意: 求一棵子树,关 ...

  8. 【洛谷P5018】对称二叉树

    题目大意:定义对称二叉树为每个节点的左右子树交换后与原二叉树仍同构的二叉树,求给定的二叉树的最大对称二叉子树的大小. 代码如下 #include <bits/stdc++.h> using ...

  9. P5018 对称二叉树题解

    题目内容链接: 那么根据题意,上图不是对称二叉树,只有节点7的子树是: 通俗来说,对称二叉树就是已一个节点x为根的子树有穿过x点的对称轴并且对称轴两边的对称点的大小也必须相等,那么这棵树就是对称二叉树 ...

随机推荐

  1. JVM 介绍

    JVM 介绍: JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的 ...

  2. 怎样手写一个Object.create()方法

    Object.create()会将参数对象作为一个新创建的空对象的原型, 并返回这个空对象, 基于这个功能, 就有了下面这个Object.create()的手动实现: function _create ...

  3. Unity性能优化-遮挡剔除

    1. Occlusion Culling-遮挡剔除的含义:没有在Camear视野范围内的游戏物体不进行渲染Render(默认情况下,Unity是会渲染所有GameObject,无论Camear是否看得 ...

  4. C#基础--go to

    goto语句的用法非常灵活,你可以用它实现很多功能,但是由于goto语句的跳转影响程序的结构,在使用的时候会使人迷茫,所以一般"教材"上都不建议使用,但是用它可以实现递归,循环,选 ...

  5. webAPI中“System.Web.Http.HttpConfiguration”不包含“EnableSystemDiagnosticsTracing”的定义解决办法

    webAPI中“System.Web.Http.HttpConfiguration”不包含“EnableSystemDiagnosticsTracing”的定义 今天从 运行 WebAPI 工程的代码 ...

  6. $.serializeArray()获取不到input的value值bug问题

    今天修改form表单,发现有好几个input值保存不上,上网搜索了一下是$.serializeArray()获取不到disabled的值.如果想要让input元素变为不可用,可以把input设为rea ...

  7. ubuntu16.04安装aquatone

    很坑   网上的那些教程 不知道怎么搞得....  误人子弟 首先 一台服务器  ubuntu16.04 首先aquatone   github  https://github.com/michenr ...

  8. Postman --> YApi

    初始 Postman,才知其如此强大,慢慢接触学习吧~ “Modern software is built on APIs,Postman helps you develop APIs faster” ...

  9. LINQ图解教程

    LINQ 什么是LINQLINQ提供程序 匿名类型 方法语法和查询语法查询变量查询表达式的结构 from子句join子句什么是联结查询主体中的from…let…where片段 from子句let子句w ...

  10. 2018 CERC 混合博弈

    N堆石子 先手最多拿A个 后手最多拿B个 每次都至少要拿一个 谁先取完谁赢 如果A和B相等直接就是一个bash博弈 如果一个石堆的石子数少于min(A,B) 则是个nim游戏 我们先讨论只有N=1且A ...