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

news/2024/4/20 16:05:57/文章来源:https://blog.csdn.net/yanweiqi1754989931/article/details/127446341

写在前面

把黑题看成蓝题结果想了老半天感觉不对劲

本题对于理解SplaySplaySplayLCTLCTLCT结构具有至关重要的意义,值得反复思考。

可能因为我比较菜

题目思路

题目给定一个类似神经网络的东西,每个节点都具有激活层、三输入单输出,输出由输入的111的个数决定,111000多就输出111。每次修改一个外界输入,要求求根节点的输出。

首先考虑一个问题,修改外界输入对上级节点输出的影响究竟有几种:

  1. 从叶子节点开始有一段连续的输入111的个数为111的节点在这里插入图片描述
    不难发现,此时如果将121212号节点修改为111,那么因此的改变到333号点(第一个非111点)终止,不会引起根节点的修改
  2. 同样,从叶子节点开始有一段连续的输入111个数为222的节点,此时叶节点的改变只会影响到第一个非222

那么就可以解决这个问题了,对于每个修改的叶子节点,找到向上首个非111/非222节点(对应叶节点0→10 \rightarrow 1011→01 \rightarrow 010)。

考虑使用LCT维护这个信息,对每个节点记录两个变量id1id_1id1id2id_2id2,分别表示沿当前点向上的第一个非111/非222点。然后每次修改前Access(x)Access(x)Access(x)Splay(x)Splay(x)Splay(x)就可以将信息上传到xxx待修改的xxx节点上。

但是注意,这里的xxx节点并不是输入的那个叶子节点,而是它的父亲节点,因为叶子节点没有输入只有输出,修改是没有意义的。

那么问题就来了,信息该怎样上传到xxx节点呢?我们回想LCTLCTLCT的三个关键操作:Rotate(x),Splay(x),Access(x)Rotate(x), Splay(x), Access(x)Rotate(x),Splay(x),Access(x),我们可以以上树为例来理解:
在这里插入图片描述
我们建树时全部连虚边(只连父不连子),然后执行Access(12)Access(12)Access(12),这时1∼121 \sim 12112的点全部位于一条实链上,然后我们将121212旋到根上,在这里需要注意,我们看一下Rotate()Rotate()Rotate()Splay()Splay()Splay()两个函数:

void rotate(int x) {int y = f[x], z = f[y], k = get(x);if(!isRoot(y)) ch[z][ch[z][1] == y] = x;ch[y][k] = ch[x][!k], f[ch[x][!k]] = y;ch[x][!k] = y, f[y] = x, f[x] = z;push_up(y); push_up(x);
}void update(int x) {if(!isRoot(x)) update(f[x]);push_down(x);
}void splay(int x) {update(x);for(int fa = f[x]; !isRoot(x); rotate(x), fa = f[x]) {if(!isRoot(fa)) rotate(get(fa) == get(x) ? fa : x);}push_up(x);
}

每次RotateRotateRotate后,我们会先更新原先的父亲节点的信息,再更新当前节点的信息。那么在一路将121212旋到根的过程中,我们会将到根节点路径上的点旋到xxx的子树里,并将信息更新给正在旋转过程中的xxx。那么我们考虑如何能够找到我们需要的信息:向上首个非111/非222节点,那么这些信息一定存在于其父亲节点(此处的父亲节点指的是旋转前的父亲节点)的右子树(旋转后)(感性理解,xxx的左子树为深度严格小于xxx的节点,左子树首个节点的右子树在仍然满足深度严格小于xxx的同时深度继续增大),因此我们优先从右子树继承信息,当右子树没有信息时判断当前节点是否满足,否则才从左子节点继承信息(此时更新的一般是xxx节点本身,而不是其父亲节点)。

此外,本题细节比较多,要仔细写。

Code

#include <bits/stdc++.h>
#pragma gcc optimize("O2")
#pragma g++ optimize("O2")
#define int long long
#define endl '\n'
using namespace std;const int N = 3e6 + 10;int n = 0;namespace LCT{struct Info{short in, out;int id1, id2, add_tag;void activate() { out = (in >= 2); }}tree[N];int ch[N][2], f[N], tag[N];#define ls ch[x][0]#define rs ch[x][1]inline void push_reverse(int x) { swap(ls, rs), tag[x] ^= 1; }inline void push_add(int x, int c) {tree[x].in += c;tree[x].add_tag += c;tree[x].activate();swap(tree[x].id1, tree[x].id2);}inline void push_down(int x) {if(tag[x]) {if(ls) push_reverse(ls);if(rs) push_reverse(rs);tag[x] = 0;}if (tree[x].add_tag) {if(ls) push_add(ls, tree[x].add_tag);if(rs) push_add(rs, tree[x].add_tag);tree[x].add_tag = 0;}} inline void push_up(int x) {tree[x].id1 = tree[rs].id1;tree[x].id2 = tree[rs].id2;if(!tree[x].id1) {if(tree[x].in != 1) tree[x].id1 = x;else tree[x].id1 = tree[ls].id1;}if(!tree[x].id2) {if(tree[x].in != 2) tree[x].id2 = x;else tree[x].id2 = tree[ls].id2;}}#define get(x) (ch[f[x]][1] == x)                        #define isRoot(x) (ch[f[x]][0] != x && ch[f[x]][1] != x)void rotate(int x) {int y = f[x], z = f[y], k = get(x);if(!isRoot(y)) ch[z][ch[z][1] == y] = x;ch[y][k] = ch[x][!k], f[ch[x][!k]] = y;ch[x][!k] = y, f[y] = x, f[x] = z;push_up(y); push_up(x);}void update(int x) {if(!isRoot(x)) update(f[x]);push_down(x);}void splay(int x) {update(x);for(int fa = f[x]; !isRoot(x); rotate(x), fa = f[x]) {if(!isRoot(fa)) rotate(get(fa) == get(x) ? fa : x);}push_up(x);}int access(int x) {int p;for(p = 0; x; x = f[p = x]) splay(x), rs = p, push_up(x);return p;}void makeRoot(int x) { access(x), splay(x), push_reverse(x); }int findRoot(int x) {access(x), splay(x);while(ch[x][0]) push_down(x), x = ch[x][0];splay(x);return x;}void split(int x, int y) {makeRoot(x);access(y), splay(y);}void link(int x, int y) {makeRoot(x);if(findRoot(y) != x) f[x] = y;}void cut(int x, int y) {makeRoot(x);if(findRoot(y) == x && f[y] == x && !ch[y][0]) {f[y] = ch[x][1] = 0;push_up(x);}}
}using LCT::tree;vector<int> g[N];void dfs(int u) {for(auto v : g[u]) {dfs(v);tree[u].in += tree[v].out;}if(u <= n) tree[u].activate();// cout << "The output of node " << u << " is " << tree[u].out << endl;
}inline void solve(){cin >> n;for(int i = 1; i <= n; i++) {int x1, x2, x3; cin >> x1 >> x2 >> x3;g[i].emplace_back(x1), LCT::f[x1] = i;g[i].emplace_back(x2), LCT::f[x2] = i;g[i].emplace_back(x3), LCT::f[x3] = i;}for(int i = n + 1; i <= 3 * n + 1; i++) cin >> tree[i].out;dfs(1);int q, ans = tree[1].out; cin >> q;while(q--) {int x; cin >> x;int xfa = LCT::f[x];// cout << "Query of change : input x = " << x << ", father of x is " << xfa << endl;  int add_val = (tree[x].out == 1) ? -1 : 1;LCT::access(xfa), LCT::splay(xfa);int split_node = (tree[x].out == 1) ? tree[xfa].id2 : tree[xfa].id1;// cout << "Deepest node of found : " << split_node << endl;// cout << "Add_val = " << add_val << endl; if(split_node) {LCT::splay(split_node);LCT::push_add(LCT::ch[split_node][1], add_val);// cout << "Tree[" << split_node << "].in origin value is " << tree[split_node].in << endl;tree[split_node].in += add_val;tree[split_node].activate();LCT::push_up(LCT::ch[split_node][1]);// cout << "Tree[" << split_node << "].in has been changed to " << tree[split_node].in << endl;// ans = tree[1].out;} else {LCT::push_add(xfa, add_val);LCT::push_up(xfa);ans ^= 1;}tree[x].out ^= 1;cout << ans << endl;}
}signed main(){ios_base::sync_with_stdio(false), cin.tie(0);int t = 1; // cin >> t;while(t--) solve();return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_404432.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

node.js+vue+Web的疫情大数据平台分析系统

以往的疫情防控管理事务处理主要使用的是传统的人工管理方式&#xff0c;这种管理方式存在着管理效率低、操作流程繁琐、保密性差等缺点&#xff0c;长期的人工管理模式会产生大量的文本文件与文本数据&#xff0c;这对事务的查询、更新以及维护带来不少困难。随着互联网时代的…

Google共码未来 与 C站 创造者的经历

本人仅参加一天活动 2022.9.14&#xff1b;吃喝拉撒全免费哈哈哈 大会主题&#xff1a;共码未来 looker、chromium、wouldnt、jetpack looker https://blog.csdn.net/WebEye_Marketing/article/details/116047404 chromium https://blog.csdn.net/arv002/article/details/1…

SEO和SEM的区别是什么,哪个效果更好一些

SEO指的是搜索引擎优化&#xff0c;SEM指的是搜索引擎影响&#xff0c;那么SEO和SEM的区别具体是什么&#xff1f;对于初创业的企业来说&#xff0c;哪个更好呢&#xff1f;下面&#xff0c;本文将介绍SEO和SEM的区别&#xff0c;帮助企业和公司网络人员理清这两者的优劣势。 S…

【力扣刷题】Day31——DP专题

文章目录七、子序列问题&#xff08;线性DP and 区间DP&#xff09;1、子序列&#xff08;不连续&#xff09;29.最长递增子序列&#xff08;LIS&#xff09;30. 最长公共子序列 &#xff08;LCS&#xff09;31.不相交的线2、子序列&#xff08;连续&#xff09;32. 最长连续递…

C语言中的指针

一。什么是指针&#xff1f; 在计算机科学中&#xff0c;指针&#xff08;Pointer&#xff09;是编程语言中的一个对象&#xff0c;利用地址&#xff0c;它的值直接指向&#xff08;points to&#xff09;存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元&a…

一棋盘的麦子

14天阅读挑战赛 有一个古老的传说&#xff0c;一位国王的女儿不幸落水&#xff0c;水中有很多鳄鱼&#xff0c;国王情急之下下令&#xff1a; 来&#xff0c;就把女儿嫁给他。”很多人纷纷退让&#xff0c;一个勇敢的小伙子挺身而出&#xff0c;冒着生命危险把公 一看是个穷小子…

Java程序员快速掌握前端知识

Java程序员是一个需要终身学习的岗位&#xff0c;加之技术更新迭代越来越快&#xff0c;程序员们不得不坚持提升自己&#xff0c;上班可能接触到新事物&#xff0c;下班也要抓紧时间钻研&#xff0c;才能不被时代淘汰。 前端技术&#xff0c;Java程序员可以不精通&#xff0c;…

新手如何自学python?

对于初学者来说&#xff0c;视频教程相比于书籍更加直观有效&#xff0c;可以先看视频进行学习&#xff0c;然后再看书进行深刻学习~下面就给你分享下教程以及书籍~ 网站 1. 网易公开课 https://open.163.com/ 2. 腾讯课堂 https://ke.qq.com/ 3. 中国大学慕课 https://www.…

xxl-job反序列化漏洞分析复现

01 影响范围 Xxl-Job<2.1.2&#xff0c;需要利用Hessian触发。 02 环境搭建 下载地址&#xff1a;https://github.com/xuxueli/xxl-job/releases 修改配置文件 xxl-job-2.0.1/xxl-job-admin/src/main/resources/application.properties 修改数据库信息&#xff0c;以及…

动手写数据库:实现记录管理

在数据库中&#xff0c;数据以”记录“作为一个单元来存储&#xff0c;例如一个表的“一行”就对应一条记录。假设我们有一个表叫STUDENT&#xff0c;其中有name, age, sex, class等字段&#xff0c;那么一条记录的信息就由这四个字段对应的信息合成。一条记录如何存储并不是一…

FFmpeg入门详解之110:RTSP协议讲解

RTSP亲手搭建直播点播 测试工具&#xff1a;VLC 数据源&#xff1a; 文件或本地摄像头 测试功能&#xff1a;RTSP直播点播 播放地址&#xff1a;rtsp://127.0.0.1:8554/rtspa001 服务端&#xff1a;推流 客户端&#xff1a;拉流 RTSP&#xff08;Real Time Streaming Pro…

Windows定时截屏、后台自动截屏工具,带有密码保护功能 —— 定时执行专家

目录 一、软件简介 二、使用教程 1、软件下载 2、软件的安装方法 3、无察觉自动截屏&#xff08;例如&#xff1a;间隔每 10分钟&#xff0c;执行 1次&#xff09; 一、软件简介 《定时执行专家》是一款制作精良、功能强大、简单易用、毫秒级精度、专业级的定时任务执行软…

Windows Server安全日志与系统事件变更审计

了解用户何时变更计算机内部时钟上的时间和日期。如果系统时间已变更&#xff0c;记录的事件将反映此新时间&#xff0c;而不是事件发生的实际时间。对系统时间不正确的变更可对应用程序造成严重破坏。 您可在Windows 2003 / 2008 / 2012计算机的安全日志中找到有价值信息&…

SpringBoot——可真是迅速又便捷

刚工作那会用的还是tomcat、springMVC、hibernate、mybatis、html、jsp……搭个项目可真是麻烦&#xff0c;各种复杂的结构还得打个war包配置web.xml&#xff0c;启动tomcat……后来也没做网站开发了&#xff0c;最近又看了看springboot&#xff0c;比之前那种开发web项目简单多…

测试人生 | 转行测试开发,4年4“跳”年薪涨3倍,我的目标是星辰大海(附大厂面经)!

编者按&#xff1a;本文来自霍格沃兹测试学院优秀学员TesterC&#xff0c;**从运营岗位转行外包测试&#xff0c;再到测试开发&#xff0c;从待业在家到4年4“跳”进入 BAT 大厂&#xff0c;年薪涨了3倍&#xff01;**他是如何完成如此励志的华丽转身的&#xff1f; 应学院的邀…

C++5-explicit、const的用法、mutable、常成员函数构成重载、在主函数中修改m_i的值

一、explicit的使用 explicit作用&#xff1a; 明确确定构造函数只能构造对象 代码示例&#xff1a; class A { public:A(int i 0):m_i(i){cout<<"A"<<i<<endl;}//构造函数可以用作类型转换&#xff0c;将int转换成类对象//explicit A(int i …

网络原理 --- 传输层Ⅰ UDP协议

文章目录网络原理传输层UDP 协议总结网络原理 介绍TCP/IP协议中每一层里面的核心内容~ 应用层传输层网络层数据链路层物理层 传输层 传输层主要负责端到端之间的传输,重点关注的是起点和终点 核心的协议有两个: UDP: 无连接 ,不可靠传输,面向数据报,全双工TCP : 有连接,可…

1024程序员节来了,

在中国“硅谷”西三旗&#xff0c;高精尖人才聚集地&#xff0c;一个砖头扔下来&#xff0c;砸中的10个人中&#xff0c;有7个是程序员 如今&#xff0c;程序员已发展成社会的主流职业&#xff0c;有多主流呢&#xff1f; 街头的王大妈李大爷都在讨论&#xff1a; “我儿子程…

vite+vue3+ts项目搭建之集成qiankun让其成为子应用模板(vite+vue3+ts+qiankun项目)

前言 以下操作&#xff0c;是续接之前 第四步 ——即&#xff1a;vitevue3tspiniaelement-plus项目已完成搭建好&#xff0c;可以直接业务开发了 主应用技术栈&#xff1a;vue2webpackjs 集成qiankun(微前端) 1、安装vite-plugin-qiankun npm install vite-plugin-qiankun2、…

在Eclipse 中使用 Maven 创建雅加达 EE 应用程序

在本教程中&#xff0c;我将指导大家如何在 Eclipse 中创建新的雅加达 EE 应用程序支持 Maven。 首先&#xff0c;在 Eclipse 中&#xff0c;转到“文件”&#xff0c;选择“新建”&#xff0c;然后选择“Maven 项目”&#xff1a; 要使用 Maven 创建雅加达 EE 项目&#xff0…