题解

可以发现每次修改的是这个点往上一条连续的链,如果我要把1改成0,需要满足这一段往上的一部分都有两个1

如果我要把0改成1,需要满足这一段往上的部分有两个0

对于每个点记录1的个数,发现我们只会把一棵树的2全部改成1或者把1全部改成2,这样加标记的时候可以同时维护是否全1或者是否全2,用lct维护,修改的时候access一遍,直接在平衡树上二分即可

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define MAXN 1000005
#define eps 1e-10
//#define ivorysi
using namespace std;
typedef long long int64;
typedef unsigned int u32;
typedef double db;
template<class T>
void read(T &res) {
res = 0;T f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
struct node {
int lc,rc,fa,val,lz;
bool all[2];
}tr[MAXN];
int num[MAXN * 2],N,Q,fa[MAXN * 2],d[2];
vector<int> son[MAXN];
bool isRoot(int u) {
if(!tr[u].fa) return true;
return tr[tr[u].fa].lc != u && tr[tr[u].fa].rc != u;
}
bool which(int u) {
return tr[tr[u].fa].lc == u;
} void addlz(int u,int v) {
tr[u].val += v;
tr[u].lz += v;
tr[u].all[0] = tr[u].all[1] = 0;
if(v == -1) tr[u].all[0] = 1;
if(v == 1) tr[u].all[1] = 1;
}
void pushdown(int u) {
if(tr[u].lz) {
if(tr[u].lc) addlz(tr[u].lc,tr[u].lz);
if(tr[u].rc) addlz(tr[u].rc,tr[u].lz);
tr[u].lz = 0;
}
}
void update(int u) {
for(int i = 0 ; i <= 1 ; ++i) {
tr[u].all[i] = (tr[u].val == i + 1) & tr[tr[u].lc].all[i] & tr[tr[u].rc].all[i];
}
}
void Rotate(int u) {
int v = tr[u].fa,w = tr[v].fa;
if(!isRoot(v)) {(v == tr[w].lc ? tr[w].lc : tr[w].rc) = u;}
int b = (u == tr[v].lc ? tr[u].rc : tr[u].lc);
tr[u].fa = w;tr[v].fa = u;
if(b) tr[b].fa = v;
if(u == tr[v].lc) {tr[u].rc = v;tr[v].lc = b;}
else {tr[u].lc = v;tr[v].rc = b;}
update(v);
}
void Splay(int u) {
static int que[MAXN],tot;
tot = 0;
int x;
for(x = u ; !isRoot(x) ; x = tr[x].fa) {
que[++tot] = x;
}
que[++tot] = x;
for(int i = tot ; i >= 1 ; --i) {
pushdown(que[i]);
}
while(!isRoot(u)) {
if(!isRoot(tr[u].fa)) {
if(which(tr[u].fa) == which(u)) Rotate(tr[u].fa);
else Rotate(u);
}
Rotate(u);
}
update(u);
}
void Access(int u) {
for(int x = 0 ; u ; x = u, u = tr[u].fa) {
Splay(u);
tr[u].rc = x;
update(u);
}
}
void dfs(int u) {
for(int j = 0 ; j < 3 ; ++j) {
if(son[u][j] <= N) {
dfs(son[u][j]);
tr[u].val += (tr[son[u][j]].val >= 2);
tr[son[u][j]].fa = u;
}
else {
tr[u].val += num[son[u][j] - N];
fa[son[u][j] - N] = u;
}
}
if(tr[u].val == 1) tr[u].all[0] = 1;
if(tr[u].val == 2) tr[u].all[1] = 1;
}
void Init() {
read(N);
int a;
for(int i = 1 ; i <= N ; ++i) {
for(int j = 0 ; j < 3 ; ++j) {
read(a);
son[i].pb(a);
}
}
for(int i = 1 ; i <= 2 * N + 1 ; ++i) read(num[i]);
dfs(1);
}
void Solve() {
read(Q);
int v;
d[0] = 1,d[1] = -1;
tr[0].all[0] = tr[0].all[1] = 1;
while(Q--) {
read(v);v -= N;
Access(fa[v]);
Splay(fa[v]);
if(tr[fa[v]].all[num[v]]) {
addlz(fa[v],d[num[v]]);
}
else {
int p = fa[v],res;
while(1) {
res = p;
pushdown(p);
if(tr[p].rc && !tr[tr[p].rc].all[num[v]]) {p = tr[p].rc;continue;}
if(tr[p].val != num[v] + 1) break;
if(tr[p].lc && !tr[tr[p].lc].all[num[v]]) {p = tr[p].lc;continue;}
break;
}
Splay(res);
if(tr[res].rc) addlz(tr[res].rc,d[num[v]]);
tr[res].val += d[num[v]];
update(res);
}
num[v] ^= 1;
Splay(1);
out(tr[1].val >= 2);enter;
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
}

【LOJ】#2187. 「SHOI2014」三叉神经树的更多相关文章

  1. 「SHOI2014」三叉神经树 解题报告

    「SHOI2014」三叉神经树 膜拜神仙思路 我们想做一个类似于动态dp的东西,首先得确保我们的运算有一个交换律,这样我们可以把一长串的运算转换成一块一块的放到矩阵上之类的东西,然后拿数据结构维护. ...

  2. 「SHOI2014」三叉神经树

    「SHOI2014」三叉神经树 给你一颗由\(n\)个非叶子结点和\(2n+1\)个叶子结点构成的完全三叉树,每个叶子结点有一个输出:\(0\)或\(1\),每个非叶子结点的输出为自己的叶子结点中较多 ...

  3. Loj #2192. 「SHOI2014」概率充电器

    Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ...

  4. [LOJ 2190] 「SHOI2014」信号增幅仪

    [LOJ 2190] 「SHOI2014」信号增幅仪 链接 链接 题解 坐标系直到 \(x\) 轴与椭圆长轴平行 点的坐标变换用旋转公式就可以了 因为是椭圆,所以所有点横坐标除以 \(p\) 然后最小 ...

  5. Loj #2570. 「ZJOI2017」线段树

    Loj #2570. 「ZJOI2017」线段树 题目描述 线段树是九条可怜很喜欢的一个数据结构,它拥有着简单的结构.优秀的复杂度与强大的功能,因此可怜曾经花了很长时间研究线段树的一些性质. 最近可怜 ...

  6. LOJ#2983. 「WC2019」数树

    传送门 抄题解 \(Task0\),随便做一下,设 \(cnt\) 为相同的边的个数,输出 \(y^{n-cnt}\) \(Task1\),给定其中一棵树 设初始答案为 \(y^n\),首先可以发现, ...

  7. loj#2269. 「SDOI2017」切树游戏

    还是loj的机子快啊... 普通的DP不难想到,设F[i][zt]为带上根玩出zt的方案数,G[i][zt]为子树中的方案数,后面是可以用FWT优化的 主要是复习了下动态DP #include< ...

  8. @loj - 2093@ 「ZJOI2016」线段树

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 小 Yuuka 遇到了一个题目:有一个序列 a1,a2,..., ...

  9. @loj - 3043@「ZJOI2019」线段树

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 九条可怜是一个喜欢数据结构的女孩子,在常见的数据结构中,可怜最喜 ...

随机推荐

  1. 第一节:从程序集的角度分析System.Web.Caching.Cache ,并完成基本封装。

    一. 揭开迷雾 1. 程序集准备 a.  需要给项目添加 System.Web 程序集. b.  需要给使用的地方添加两个引用. 2. 程序集探究      在对应的类中输入关键字 Cache,选中点 ...

  2. MySQL锁解决并发问题详解

    文章分为以下几个要点 问题描述以及解决过程 MySQL锁机制 数据库加锁分析 下面讨论的都是基于MySQL的InnoDB. 0. 问题描述以及解决过程 因为涉及到公司利益问题,所以下面很多代码和数据库 ...

  3. 七、uboot 代码流程分析---C环境建立

    7.1 start.S 修改 在上一节中的流程中,发现初始化的过程并没由设置看门狗,也未进行中断屏蔽 如果看门狗不禁用,会导致系统反复重启,因此需要在初始化的时候禁用看门狗:中断屏蔽保证启动过程中不出 ...

  4. CSS——margin

    CSS margin 属性 定义和用法 margin 简写属性在一个声明中设置所有外边距属性.该属性可以有 1 到 4 个值. 说明 这个简写属性设置一个元素所有外边距的宽度,或者设置各边上外边距的宽 ...

  5. elasticsearch 单机多实例

    elasticsearch 配置单机器多实例 host: - - path data: /opt/elasticsearch/data/node1 /opt/elasticsearch/data/no ...

  6. 寻路优化(一)——二维地图上A*启发函数的设计探索

    工作中需要优化A*算法,研究了一天,最后取得了不错的效果.看网上的朋友还没有相关的研究,特此记录一下.有错误欢迎大家批评指正.如需转载请注明出处,http://www.cnblogs.com/Leon ...

  7. host-only

    https://www.cnblogs.com/yaox/p/6635312.html

  8. python中datetime与string的相互转换

    >>> import datetime >>> value = '2016-10-30 01:48:31' >>> datetime.strpti ...

  9. 【转】Linux中包管理与定时任务

    [转]Linux中包管理与定时任务 第1章 软件查询 1.1 查询软件是否安装 rpm -qa |grep cron 查询是否安装了这个软件. [root@znix ~]# rpm -qa |grep ...

  10. STM32F103X datasheet学习笔记---Interrupts and events

    1.前言 本章主要介绍STM32中断和事件相关的内容 2.NVIC NVIC管理着包括内核异常等中断 主要特性 68个外部中断源(不包含16个内部中断线) 可编程优先级为16级 低延迟异常和中断处理 ...