题面挺有意思(恶心)的。

传送门:P4332 [SHOI2014]三叉神经树

LCT

Solution

1

对于每一个非叶子节点 iii,有 valival_ivali​,表示其输出为 1 的儿子的总数。所以对于每一个 vali,i∈[1,n]val_i,\ i \in [1,n]vali​, i∈[1,n] ,其取值范围是 0~3。所以我们发现这个非叶子节点 iii 最后输出的结果就是 ⌊vali2⌋\left\lfloor\dfrac{val_i}{2}\right\rfloor⌊2vali​​⌋。

而对于叶子节点 jjj(即编号范围为 (n,3∗n+1](n, 3 *n +1](n,3∗n+1]),假设它的输出是 xxx(xxx 为 0 或 1),为了保证其输出结果是 ⌊valj2⌋\left\lfloor\dfrac{val_j}{2}\right\rfloor⌊2valj​​⌋,我们使 valj←x∗2val_j \gets x *2valj​←x∗2。所以对于每个 valj,j∈(n,3∗n+1]val_j,\ j \in (n, 3 * n + 1]valj​, j∈(n,3∗n+1],其取值只有 0 或 2 两种可能性

对于 valvalval 的计算,我们可以在输入后拓扑排序得到。

2

我们都会模拟暴力过程——先改叶子节点(先默认为 0 改为 1),如果它的父亲此时权值为 1 的儿子数量从原来小于 0 的变成大于 0 的,那么父亲的权值也要改。以此类推,直到有一个节点输出状态没有变化,那么它的所有祖先肯定不会变。

通过模拟我们发现,每次修改的一定是一段自底向上的连续区间!

接着也就不难想到,只有当点权为 1 时,才能通过修改点权变成 2,使输出由 0 变成 1,从而继续引发祖先的变化。那么我们需要知道的就是,对于每一个叶子节点,它自底向上的连续一段点权为 1 的部分。

再讨论叶子节点 1 改 0 的情况,同理也可以发现我们还要维护自底向上的连续一段点权为 2 的部分。

”——摘自洛谷P4332 [SHOI2014]三叉神经树题解 by FlashHu

大佬已经说得很清楚了,要维护区间,所以使用 LCT,同时间维护两个数组 n1n1n1 和 n2n2n2。

n1xn1_xn1x​ 表示从 xxx 节点出发,往父亲节点的方向走,第一个权值(即 valvalval)不为 1 的节点编号。n2n2n2 同理。

每次我们先打通(即 accessaccessaccess)到叶子节点 xxx 的父亲节点 fxf_xfx​(因为至少是从 fxf_xfx​ 开始造成影响),再 splay(f[x])splay(f[x])splay(f[x]),(假设 xxx 是由 0 变为 1)然后 splay(n1[f[x]])splay(n1[f[x]])splay(n1[f[x]])。

这样一来,会发生改变(即 valvalval 在 1 和 2 之间变换)的部分就是 n1[f[x]]n1[f[x]]n1[f[x]] 的右子树了。所以最后我们对该右子树进行区间修改,对 n1[f[x]]n1[f[x]]n1[f[x]] 进行单点修改。

3

如何区间修改。

发现那些需要进行修改的区间,内部所有的节点的权值要么都是 1,否则就都是 2。而我们对它们的操作无非就是:

  • 点权为 2,减 1;
  • 点权为 1,加 1。

所以,我们实际上只用对这个区间做一个类似“翻转”的操作(可以理解为在权值方面的翻转)即可。

Code

吐槽:FlashHu 大佬的代码太难理解了!!!

#include<bits/stdc++.h>
using namespace std;#define rep(i, a, b) for(register int i = a; i <= b; ++i)
#define ls c[x][0]
#define rs c[x][1]
const int maxn = 5e5 + 5, maxm = 15e5 + 5;
int n, qu;
int f[maxm], val[maxm];
int c[maxn][2], tag[maxn], n1[maxn], n2[maxn];
int d[maxn];
int tp, nwrt;
queue <int> q;inline int rd()
{int s = 0, x = 1;char ch = getchar();while(ch < '0' or ch > '9') {if(ch == '-') x = -1; ch = getchar();}while(ch >= '0' and ch <= '9') s = s * 10 + ch - '0', ch = getchar();return x * s;
}inline bool nrt(int p)
{int x = f[p]; return ls == p or rs == p;
}inline void up(int x)//为了尽可能深,所以先右子树再当前节点最后左子树
{int &p = n1[x], &q = n2[x];p = n1[rs]; if(!p) p = x * (val[x] != 1); if(!p) p = n1[ls];q = n2[rs]; if(!q) q = x * (val[x] != 2); if(!q) q = n2[ls];
}inline void dw(int x, int k)
{int &v = val[x];if(v == 2) v = 1; else v = 2;swap(n1[x], n2[x])/*容易发现更改权值的时候n1n2也跟着翻转了*/, tag[x] += k;
}inline void all(int x)
{int &tm = tag[x];if(nrt(x)) all(f[x]);if(tm) dw(ls, tm), dw(rs, tm), tm = 0;
}inline void rotate(int x)
{int y = f[x], z = f[y], k = (c[y][1] == x), w = c[x][!k];if(nrt(y)) c[z][c[z][1] == y] = x; f[x] = z, c[y][k] = w;if(w) f[w] = y; c[x][!k] = y, f[y] = x; up(y);
}inline void splay(int x)
{all(x);while(nrt(x)){int y = f[x], z = f[y];if(nrt(y)) rotate((c[z][1] == y) ^ (c[y][1] == x) ? x : y);rotate(x);}up(x);
}inline void access(int x)
{for(int lst = 0; x; x = f[lst = x])splay(x), rs = lst, up(x);
}int main()
{n = rd();rep(i, 1, n)f[rd()] = f[rd()] = f[rd()] = i, d[i] = 3/*入度*/;rep(i, n + 1, 3 * n + 1)//叶子节点 q.push(i), val[i] = rd() << 1;while(!q.empty())//拓扑排序 {int u = q.front(); q.pop();if(u <= n) up(u);val[f[u]] += (val[u] >> 1), d[f[u]] -= 1;if(!d[f[u]]) q.push(f[u]);}nwrt = val[1] >> 1, qu = rd();while(qu--) {int x = rd(), &v = val[x]/*该叶子节点原本输出的值*/;if(!v) v = 2/*更改输出值*/, tp = 1/*标记输出值是从 0 变成 1*/; else v = 0, tp = -1;access(x = f[x]), splay(x);if((tp > 0 ? n1 : n2)[x]){splay(x = (tp > 0 ? n1 : n2)[x]);dw(rs, tp), up(rs);//区间修改 val[x] += tp, up(x);//单点修改 }else dw(x, tp), up(x), nwrt ^= 1;printf("%d\n", nwrt/*优化,省时间*/);}return 0;
}

——EndEndEnd——

【LG-P4332 [SHOI2014]】三叉神经树 题解相关推荐

  1. P4332 [SHOI2014]三叉神经树(LCT)

    Luogu4332 LOJ2187 题解 代码-Tea 题意 : 每个点有三个儿子 , 给定叶节点的权值\(0\)或\(1\)且支持修改 , 非叶子节点的权值为当有\(>=2\)个儿子的权值为\ ...

  2. [LCT刷题][树链信息维护] P4332 [SHOI2014]三叉神经树

    写在前面 把黑题看成蓝题结果想了老半天感觉不对劲 本题对于理解 S p l a y Splay Splay和 L C T LCT LCT结构具有至关重要的意义,值得反复思考. 可能因为我比较菜 题目思 ...

  3. SHOI2014 三叉神经树

    传送门 一道非常好的LCT/树剖题.但是像我这样的菜鸡想不到什么有效做法-- 首先我们可以很容易发现,一次如果要在链上连续修改那么肯定是从底向上的一端连续区间.如果我们把每个节点的输入值作为其权值,那 ...

  4. [SHOI2014]三叉神经树

    Description: 计算神经学作为新兴的交叉学科近些年来一直是学术界的热点.一种叫做SHOI 的神经组织因为其和近日发现的化合物 SHTSC 的密切联系引起了人们的极大关注. SHOI 组织由若 ...

  5. 洛谷P4315 月下“毛景树” 题解

    洛谷P4315 月下"毛景树" 题解 题目链接:P4315 月下"毛景树" 题意:请维护一个数据结构,支持 改第 kkk 条边的边权 结点 uuu 到 vvv ...

  6. 三叉神经树 ( neuron )

    三叉神经树 ( neuron ) 题目描述 计算神经学作为新兴的交叉学科近些年来一直是学术界的热点.一种叫做SHOI 的神经组织因为其和近日发现的化合物SHTSC 的密切联系引起了人们的极大关注. S ...

  7. P4332-[SHOI2014]三叉神经树【LCT】

    正题 题目链接:https://www.luogu.com.cn/problem/P4332 题目大意 给出nnn个点的一棵有根三叉树,保证每个点的儿子个数为333或者000,每个叶子有一个权值000 ...

  8. NOI2020D2T2超现实树题解

    题意 NNN 组数据,每组数据给定 mmm 棵二叉树,其中每棵树有 nnn 个节点. 定义一次操作为将 mmm 棵二叉树中任意一棵树的叶节点换成任意一棵二叉树,问进行若干次这样的操作后形成的树的集合是 ...

  9. [八省联考 2018] 林克卡特树 题解

    这道题我前前后后做了一年,共过了 4 4 4 遍,每次都有的新的理解:这次我认为自己理解透了,于是就写了一篇题解. 这道题是我入坑看到的第一道黑题(当时很萌,不知道黑题是什么,看到这题感觉很好玩),另 ...

最新文章

  1. python如何安装pip3_如何在安装pip3以及第三方python库
  2. gorilla/mux 的学习
  3. sqlite java blob_【转】好东西!sqlite3中BLOB数据类型存储大对象运用示例
  4. Python-多线程编程
  5. libcurl 发送邮件_结合MIME C++ library与CURL发送带附件的邮件
  6. pdf虚拟打印机下载win7_闪电PDF虚拟打印机使用教程,超级简单的方法
  7. 澎湖师傅共制巨型“米龟” 延续两岸“乞龟”祈福民俗
  8. SpringBoot整合jsp技术
  9. RN开发环境搭建-window
  10. linux sync 同步文件夹,linux-日常运维-文件同步工具-rsync
  11. 2022年各国程序员薪资排名!
  12. OSError: [Errno 8] Exec format error
  13. 自动化测试工具 Selenium WebDriver 入门教程
  14. 微信小程序 逆向还原
  15. 电脑云便签怎么在桌面日历月视图上新增便签记录事情?
  16. Xilinx SDx 2018.3安装
  17. 苹果微信多开_微信双开是什么?是不是需要两个手机号?
  18. 华为要做视频?苏杰称只是配合终端不涉足内容
  19. 学习51单片机DAC工作原理
  20. # 算法百题斩其一: floodfill

热门文章

  1. npm 创建第一个Angular项目
  2. springboot运行自动关闭Completed shut down of DiscoveryClient的解决方法
  3. java编程初学者要注意的几点
  4. git点击pull后没有同步_关于git pull时出现的问题及解决反思
  5. CSS下划线与文字间距,下划线粗细以及下划线颜色的设置
  6. Spark SQL概述
  7. ZOJ 1036: 算菜价
  8. 批量保存拼多多批发商城商品主图及视频
  9. 验证码、文件上传和中间件
  10. Kaptcha:验证码生成