3553: [Shoi2014]三叉神经树(树链剖分)
这道题特别恶心,首先我们可以发现更改的就是出现连续的一或二,那么就用线段树+树链剖分找到这个范围
想到是不难想,就是打起来恶心罢了= =
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;
}