\(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. vue.js移动端app:初始配置

    本系列将会用vue.js2制作一个移动端的webapp单页面,页面不多,大概在7,8个左右,不过麻雀虽小,五脏俱全,常用的效果如轮播图,下拉刷新,上拉加载,图片懒加载都会用到.css方面也会有一些描述 ...

  2. shell习题第22题:

    [题目要求] 加入A服务器可直接ssh到B,不用输入密码.A和B都有一个目录是/data/web/这下有很多文件,我们不知道这下面有多少层目录,但是之前的目录结构和文件是一模一样的.但是现在不确定是否 ...

  3. vsftp多个用户公享同一个文件,但是权限不同

    如标题:vsftp多个用户公享同一个文件,但是权限不同.如何做到呢.首先创建多个用户,并且指定同一个目录

  4. sqlserver时间戳

    SELECT DATEADD(S,1576464113 + 8 * 3600,'1970-01-01 00:00:00') --时间戳转换成普通时间 SELECT DATEDIFF(S,'1970-0 ...

  5. 【爬虫集合】Python爬虫

    一.爬虫学习教程 1. https://www.jianshu.com/u/c32d557edfa3 2. WebMagic是一个简单灵活的Java爬虫框架.基于WebMagic,你可以快速开发出一个 ...

  6. axios全局配置及拦截器

    axios使用说明文档 axios 全局配置: //axios-init.js import axios from 'axios': let loadingInstance; //创建Loading ...

  7. opencv-01--图像的遍历

    遍历图像的4种方式 一.at<typename>(i,j) Mat类提供了一个at的方法用于取得图像上的点,它是一个模板函数,可以取到任何类型的图像上的点.下面我们通过一个图像处理中的实际 ...

  8. 同步/异步/阻塞/非阻塞/BIO/NIO/AIO

    转摘自:https://www.cnblogs.com/lixinjie/p/a-post-about-io-clearly.html 常规的误区 假设有一个展示用户详情的需求,分两步,先调用一个HT ...

  9. Opencl 学习笔记

    1. HelloWorld

  10. ligerui.grid.extend.rowSpan

    扩展LigerUI的Grid中的相同列合并行功能,代码如下:$.extend($.ligerui.controls.Grid.prototype, { _getHtmlFromData:functio ...