这道题特别恶心,首先我们可以发现更改的就是出现连续的一或二,那么就用线段树+树链剖分找到这个范围

想到是不难想,就是打起来恶心罢了= =

CODE:

#include<cstdio>

#include<iostream>

#include<cstring>

#include<algorithm>

#include<stack>

using namespace std;

#define maxn 500100

struct edges{

int to,next;

}edge[maxn*3];

int l,next[maxn];

int addedge(int x,int y) {

edge[++l]=(edges){y,next[x]};next[x]=l;

}

int s[maxn],ch[maxn],fa[maxn*3],ans[maxn*3],q[maxn];

int bfs() {

int r=0;

q[++r]=1;

int l=0;

while (l<r) {

int u=q[++l];s[u]=1;

for (int i=next[u];i;i=edge[i].next) {

fa[edge[i].to]=u;q[++r]=edge[i].to;

}

}

for (int i=r;i;i--) {

s[fa[q[i]]]+=s[q[i]];

ch[fa[q[i]]]=s[ch[fa[q[i]]]]<s[q[i]]?q[i]:ch[fa[q[i]]];

ans[fa[q[i]]]+=ans[q[i]]>1?1:0;

}

}

int add[maxn],pos[maxn],pre[maxn];

int cnt;

bool b[maxn];

int heavy(int x,bool y) {

stack<int > s;

s.push(1);

add[pos[++cnt]=1]=cnt;

pre[1]=1;

while (!s.empty()) {

int x=s.top();s.pop();

if (!b[x]&&ch[x]) {

s.push(x);

s.push(ch[x]);

add[pos[++cnt]=ch[x]]=cnt;

pre[ch[x]]=pre[x];

b[x]=1;

continue;

}

for (int i=next[x];i;i=edge[i].next) {

if (edge[i].to!=ch[x]) {

s.push(x);

s.push(edge[i].to);

add[pos[++cnt]=edge[i].to]=cnt;

pre[edge[i].to]=edge[i].to;

next[x]=edge[i].next;

break;

}

}

}

return 0;

}

struct bo {

int sz,s,len;

};

struct node{

int l,r,lz;bo b;

}t[maxn*8];

#define s(x) t[x].b.s

#define sz(x) t[x].b.sz

#define len(x) t[x].b.len

bo update(bo l,bo r) {

bo ans;

ans.sz=l.sz+r.sz;

ans.s=r.s;

ans.len=r.len;

if (l.s==r.s&&r.len==r.sz) ans.len+=l.len;

return ans;

}

#define lc(x) (x<<1)

#define rc(x) ((x<<1)+1)

#define mid ((r+l)>>1)

#define upd(x) t[x].b=update(t[lc(x)].b,t[rc(x)].b)

void build(int x,int l,int r) {

t[x].l=l;t[x].r=r;

sz(x)=r-l+1;

if (l==r) {s(x)=ans[pos[l]];len(x)=1;return ;}

build(lc(x),l,mid);build(rc(x),mid+1,r);

upd(x);

}

#define lz(x) t[x].lz

void pushback(int x) {

if (t[x].lz==0) return;

int l=lc(x),r=rc(x);

lz(l)+=lz(x);lz(r)+=lz(x);

s(l)+=lz(x);s(r)+=lz(x);

lz(x)=0;

}

bo que(int x,int y) {

int l=t[x].l,r=t[x].r;

if (r<=y) return t[x].b;

pushback(x);

if (y<=mid) return que(lc(x),y);

if (y>mid) return update(que(lc(x),y),que(rc(x),y));

}

void inc(int x,int x1,int y1,int z) {

int l=t[x].l,r=t[x].r;

if (y1<l||x1>r) return ;

if (x1<=l&&r<=y1) {

t[x].lz+=z;

s(x)+=z;

return ;

}

pushback(x);

inc(lc(x),x1,y1,z);inc(rc(x),x1,y1,z);

upd(x);

}

void gen(int x,int flag) {

while (x) {

bo tmp=que(1,add[x]);

switch (flag) {

case 0:

if (tmp.s==2) {

if (tmp.len>=add[x]-add[pre[x]]+1) {

inc(1,add[pre[x]],add[x],-1);

x=fa[pre[x]];

} else {

inc(1,add[x]-tmp.len,add[x],-1);

x=0;

}

}else {

inc(1,add[x],add[x],-1);

x=0;

}

break;

case 1:

if (tmp.s==1) {

if (tmp.len>=add[x]-add[pre[x]]+1) {

inc(1,add[pre[x]],add[x],1);

x=fa[pre[x]];

} else {

inc(1,add[x]-tmp.len,add[x],1);

x=0;

}

}else {

inc(1,add[x],add[x],1);

x=0;

}

break;

}

}

return ;

}

int main(){

int n;

scanf("%d",&n);

for (int i=1;i<=n;i++) {

int x1,x2,x3;

scanf("%d%d%d",&x1,&x2,&x3);

if (x1<=n) addedge(i,x1);else fa[x1]=i;

if (x2<=n) addedge(i,x2);else fa[x2]=i;

if (x3<=n) addedge(i,x3);else fa[x3]=i;

}

for (int i=1;i<=2*n+1;i++) {

scanf("%d",&ans[i+n]);

ans[fa[i+n]]+=ans[i+n];

}bfs();

heavy(1,1);

build(1,1,n);

int Q;

scanf("%d",&Q);

while (Q--) {

int x;

scanf("%d",&x);

ans[x]^=1;

gen(fa[x],ans[x]);

printf("%d\n",que(1,1).s>=2?1:0);

}

return 0;

}

3553: [Shoi2014]三叉神经树(树链剖分)的更多相关文章

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

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

  2. 线段树&数链剖分

    傻逼线段树,傻逼数剖 线段树 定义: 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 使用线段树可以快速的查找某一个节点在若干条线段中出现 ...

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

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

  4. 【BZOJ-3553】三叉神经树 树链剖分

    3553: [Shoi2014]三叉神经树 Time Limit: 160 Sec  Memory Limit: 256 MBSubmit: 347  Solved: 112[Submit][Stat ...

  5. [LOJ3014][JOI 2019 Final]独特的城市——树的直径+长链剖分

    题目链接: [JOI 2019 Final]独特的城市 对于每个点,它的答案最大就是与它距离最远的点的距离. 而如果与它距离为$x$的点有大于等于两个,那么与它距离小于等于$x$的点都不会被计入答案. ...

  6. UOJ#30/Codeforces 487E Tourists 点双连通分量,Tarjan,圆方树,树链剖分,线段树

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ30.html 题目传送门 - UOJ#30 题意 uoj写的很简洁.清晰,这里就不抄一遍了. 题解 首先建 ...

  7. BZOJ1758[Wc2010]重建计划——分数规划+长链剖分+线段树+二分答案+树形DP

    题目描述 输入 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai, ...

  8. CF487E Tourists 圆方树、树链剖分

    传送门 注意到我们需要求的是两点之间所有简单路径中最小值的最小值,那么对于一个点双联通分量来说,如果要经过它,则一定会经过这个点双联通分量里权值最小的点 注意:这里不能缩边双联通分量,样例\(2\)就 ...

  9. 2019.01.08 codeforces 1009F. Dominant Indices(长链剖分)

    传送门 长链剖分模板题. 题意:给出一棵树,设fi,jf_{i,j}fi,j​表示iii的子树中距离点iii距离为jjj的点的个数,现在对于每个点iii要求出使得fif_ifi​取得最大值的那个jjj ...

随机推荐

  1. ARM处理器寄存器

    参考:ARM Architecture Reference Manual的39页 1.ARM处理器寄存器纵览 ARM微处理器共有37个32位寄存器,其中31个为通用寄存器(R13和R13_svc不是同 ...

  2. 3)Javascript设计模式:Observer模式

    Observer模式 var Observer = (function() { var instance = null; function Observe() { this.events = {} } ...

  3. UVa 594 - One Little, Two Little, Three Little Endians

    题目大意:大小端模式的转换.所谓的小端模式,是指数据的高位保存在内存的高地址中,而数据的低位保存在内存的低地址中.与此相对,所谓的大端模式,是指数据的高位,保存在内存的低地址中,而数据的低位,保存在内 ...

  4. keystore 介绍

    Keytool 是一个有效的安全钥匙和证书的管理工具. Java 中的 keytool.exe (位于 JDK\Bin 目录下)可以用来创建数字证书,所有的数字证书是以一条一条(采用别名区别)的形式存 ...

  5. 滚动视图(ScrollView)的功能与用法

    滚动视图ScrollView由FrameLayout派生而出,它就是一个用于为普通组件添加滚动条的组件.ScrollView里最多只能包含一个组件,而ScrollVew的作用就是为该组件添加垂直滚动条 ...

  6. Sql server2014 内存优化表 本地编译存储过程

    参考文献:http://www.infoq.com/cn/news/2013/09/Compiled-Queries http://www.bianceng.cn/database/SQLServer ...

  7. 百度人脸识别api及face++人脸识别api测试(python)

    一.百度人脸识别服务 1.官方网址:http://apistore.baidu.com/apiworks/servicedetail/464.html 2.提供的接口包括: 2.1 多人脸比对:请求多 ...

  8. SQLSERVER如何导入数据保持ID不变(ID为自增主键)

    使用SQL SERVER最操蛋的就是导入数据,以前用企业管理器直接导数据,导一次骂N次娘,在骂了微软无数次娘之后总结了一个方法揍合着还算受用. 其核心要点就是要将数据结构导入到目标数据库服务器上,再来 ...

  9. UWP 律师信息 MVVM 2.0版本

    由于1.0版本存在一个很大的BUG,一直也没有找到问题所在,后来,一位在微软的朋友说,他们的测试小妹给出的结果是框架的问题,所以,就直接整体重构了代码,也布局设计上,由跳转页面变为了UWP常见的左侧列 ...

  10. CMD修改IP地址

    在操作系统下,我们可以使用"本地连接"的属性来修改IP地址,但是如果我们要在多个IP地址之间切换,使用这种方法未免过于麻烦.我们可以使用NETSH命令来添加,相当简便.使用DOS修 ...