好久之前做的题了QWQ

现在来补一发博客

一道神仙题啊。。qwq

首先,我们可以看出来,我们如果对于每个点维护一个\(val\),表示他的直系儿子中有几个表现为1的。

那么\(val[x]>>1\) 就是他反应的类型

这样十分便于我们计算一开始的\(val\)

那么考虑修改。

一定是会修改一条\(连续1(对应着0->1),或者连续2(1->0)\)

也就是说,如果我们能够知道一次修改,\(1到x\)的路径下最下面的1或者2的位置,我们就能够通过链修改来实现。

其实一开始我想的是二分

我们发现,可以通过\(LCT\)维护最深的不是\(1\)的位置和不是\(2\)的位置\(num1和num2\)

那么我们对于一次修改,假设由\(0修改成1\)

如果\(num1==0\),那么说明整条链都会被修改,直接修改整条路径

不然,我们就将路径提出来,\(splay(num1)\)之后,修改他的右儿子,表示他下面的点。

然后把当前点的\(val\)修改,但是不改变别的量。

QWQ有一些细节,对于修改的时候,由于路径上的\(val\)都是1或者2。

所以修改的之后可以直接\(xor\ 2\)

具体细节看代码实现吧

里面有详细的注释

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<set>
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 2e6+1e2;
int ch[maxn][3];
int fa[maxn],val[maxn];
int tag[maxn];
int n,m;
int num1[maxn],num2[maxn]; //深度最深的 儿子数不为1 或者 2 的 节点是的编号
int st[maxn];
int son(int x)
{
if (ch[fa[x]][0]==x) return 0;
else return 1;
}
bool notroot(int x)
{
return ch[fa[x]][0]==x || ch[fa[x]][1]==x;
}
void update(int x) //由于是深度最深,我们一定是先考虑右子树,再说当前点,再是右子树
{
num1[x]=num1[ch[x][1]];
if (!num1[x] && val[x]!=1) num1[x]=x;
if (!num1[x]) num1[x]=num1[ch[x][0]];
num2[x]=num2[ch[x][1]];
if (!num2[x] && val[x]!=2) num2[x]=x;
if (!num2[x]) num2[x]=num2[ch[x][0]];
}
void solve(int x,int d)
{
val[x]^=3;
swap(num1[x],num2[x]); //修改的时候,必定是一段全为1或者2的区间,所以一个一定是0,直接交换是没错的
tag[x]+=d;
}
void pushdown(int x)
{
if (tag[x])
{
if (ch[x][0]) solve(ch[x][0],tag[x]);
if (ch[x][1]) solve(ch[x][1],tag[x]);
tag[x]=0;
}
}
void rotate(int x)
{
int y=fa[x],z=fa[y];
int b=son(x),c=son(y);
if (notroot(y)) ch[z][c]=x;
fa[x]=z;
ch[y][b]=ch[x][!b];
fa[ch[x][!b]]=y;
ch[x][!b]=y;
fa[y]=x;
update(y);
update(x);
}
void splay(int x)
{
int y=x,cnt=0;
st[++cnt]=y;
while (notroot(y)) y=fa[y],st[++cnt]=y;
while (cnt) pushdown(st[cnt--]);
while (notroot(x))
{
int y=fa[x],z=fa[y];
int b=son(x),c=son(y);
if (notroot(y))
{
if (b==c) rotate(y);
else rotate(x);
}
rotate(x);
}
update(x);
}
void access(int x)
{
for (int y=0;x;y=x,x=fa[x])
{
splay(x);
ch[x][1]=y;
update(x);
}
}
int in[maxn];
queue<int> q;
int main()
{
n=read();
for (int i=1;i<=n;i++)
{
int x=read(),y=read(),w=read();
in[i]=3;
fa[x]=fa[y]=fa[w]=i;
}
for (int i=n+1;i<=3*n+1;i++) val[i]=read()*2,q.push(i); //我们事先val都*2,那么对于每个点,他表现出来的特征就是val>>1
int m=read();
while (!q.empty()) //拓扑排序先预处理出来每个点的val
{
int x=q.front();
q.pop();
if (x<=n) update(x);
val[fa[x]]+=val[x]/2;
in[fa[x]]--;
if (!in[fa[x]]) q.push(fa[x]);
}
int ans=val[1]>>1;
//在本题中,val表示儿子的表示1的数量,那么val>>1就相当于每个点表达的信息
for (int i=1;i<=m;i++)
{
int x=read();
val[x]^=2; //叶子节点只有可能是0或者1,而乘2之后就是0或者2
int k = val[x] - 1;
x=fa[x]; //不修改底下的叶子节点
access(x);
splay(x); //打通这个点到1的路径
int now;
if (k==-1) now = num2[x];
else now = num1[x];
if (!now)
{
solve(x,k);
update(x);
ans^=1;
}
else
{
splay(now);
solve(ch[now][1],k);
update(ch[now][1]);
val[now]+=k;
update(now);
}
cout<<ans<<"\n";
}
return 0;
}

洛谷4322 SHOI2014 三叉神经树(LCT+思维)的更多相关文章

  1. 洛谷P4332 [SHOI2014]三叉神经树(LCT,树剖,二分查找,拓扑排序)

    洛谷题目传送门 你谷无题解于是来补一发 随便百度题解,发现了不少诸如树剖\(log^3\)LCT\(log^2\)的可怕描述...... 于是来想想怎么利用题目的性质,把复杂度降下来. 首先,每个点的 ...

  2. 洛谷P4332 [SHOI2014]三叉神经树(LCT)

    传送门 FlashHu大佬太强啦%%% 首先,我们可以根据每一个点的权值为$1$的儿子的个数把每个点记为$0~3$,表示这一个点的点权 先考虑一下暴力的过程,假设从$0$变为$1$,先更改一个叶子结点 ...

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

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

  4. BZOJ 3553: [Shoi2014]三叉神经树 LCT

    犯傻了,想到了如果是 0->1 的话就找最深的非 1 编号,是 1 -> 0 的话就找最深的非 0 编号. 但是没有想到这个东西可以直接维护. 假设不考虑叶子节点,那么如果当前点的值是 1 ...

  5. 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)

    To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...

  6. 【BZOJ2830/洛谷3830】随机树(动态规划)

    [BZOJ2830/洛谷3830]随机树(动态规划) 题面 洛谷 题解 先考虑第一问. 第一问的答案显然就是所有情况下所有点的深度的平均数. 考虑新加入的两个点,一定会删去某个叶子,然后新加入两个深度 ...

  7. [BZOJ 3553][SHOI2014]三叉神经树

    传送门(下面也有题面) 题目大意: 一颗有根树,每个非叶子节点都有三个子节点,每个节点的权为0/1. 每个节点的权 取决于其所有子节点中 哪种权出现的次数更多. 有若干次询问,每次询问修改一个叶子节点 ...

  8. 洛谷 P4284 [SHOI2014]概率充电器 概率与期望+换根DP

    洛谷 P4284 [SHOI2014]概率充电器 概率与期望+换根DP 题目描述 著名的电子产品品牌\(SHOI\) 刚刚发布了引领世界潮流的下一代电子产品-- 概率充电器: "采用全新纳米 ...

  9. 洛谷AT2342 Train Service Planning(思维,动态规划,珂朵莉树)

    洛谷题目传送门 神仙思维题还是要写点东西才好. 建立数学模型 这种很抽象的东西没有式子描述一下显然是下不了手的. 因为任何位置都以\(k\)为周期,所以我们只用关心一个周期,也就是以下数都在膜\(k\ ...

随机推荐

  1. LeetCode《买卖股票的最佳时机》系列题目,最详解

    目录 说在前面 引例:只能交易一次 一.动态数组定义 二.状态转移方程 三.初始化 四.优化 无限制买卖 一.动态数组定义 二.状态转移方程 三.初始化 四.优化 交易 2 次,最大利润? 一.动态数 ...

  2. 用CUDA写出比Numpy更快的规约求和函数

    技术背景 在前面的几篇博客中我们介绍了在Python中使用Numba来写CUDA程序的一些基本操作和方法,并且展示了GPU加速的实际效果.在可并行化的算法中,比如计算两个矢量的加和,或者是在分子动力学 ...

  3. Qt 自定义事件

    Qt 自定义事件很简单,同其它类库的使用很相似,都是要继承一个类进行扩展.在 Qt 中,你需要继承的类是 QEvent. 继承QEvent类,你需要提供一个QEvent::Type类型的参数,作为自定 ...

  4. 110_SSM框架

    目录 需求分析->功能设计->数据库设计 环境要求 环境 要求 数据库环境 基本环境搭建 创建maven项目 pom.xml添加依赖,添加资源导出 idea连接数据库 提交项目到Git 创 ...

  5. MySQL实战45讲(21--25)-笔记

    21 | 为什么我只改一行的语句,锁这么多? 加锁规则里面:包含了两个"原则".两个"优化"和一个"bug". 原则 1:加锁的基本单位是 ...

  6. [源码解析] 深度学习分布式训练框架 horovod (21) --- 之如何恢复训练

    [源码解析] 深度学习分布式训练框架 horovod (21) --- 之如何恢复训练 目录 [源码解析] 深度学习分布式训练框架 horovod (21) --- 之如何恢复训练 0x00 摘要 0 ...

  7. python语言介绍及安装

    Python语言简介 Python是什么语言 Python是一种解释型的.可移植的.开源的脚本. 什么是计算机编程 计算机程序:为了让计算机执行某些操作或解决某个问题而编写的一系列有序指令的集合 如何 ...

  8. ACID的实现原理

    引言 ACID是事务的特点也是必须的要求,只有保证ACID事务的执行才不会出错,分别是原子性.一致性.隔离性和持久性.我们知道典型的MySQL事务是这样执行的: start transaction 开 ...

  9. dede织梦会员模板调用template下模板head.htm方法及解析变量

    1.找到dedecms会员中心的的目录 member ,然后在目录下用编辑器打开config.php 加入对dede模板解释函数如下:   //php脚本开始 //引入arc.partview.cla ...

  10. 如何使用SQL的备份文件(.bak)恢复数据库

    出于很多情况,数据库只剩下.bak文件,想要恢复数据库,找了很多资料才知道可以这样!!!!! 个人觉得图片教程更有意义,请看步骤: 1.选中"数据库" 右击 选择"还原数 ...