[SHOI2014] 三叉神经树
题意:
给你一个有$n$个非叶节点的完满三叉树(每个点要么有三个儿子要么没有儿子)。
那么显然这棵树共有$2n+1$个叶节点。每个叶节点有一个0/1的权值。
每个非叶节点的权值等于它的儿子中权值的众数,也就是儿子的权值和/2。
现在有$q$次修改,每次将一个叶子的权值取反,问每次修改之后根节点的权值是什么。
$n,q\leq 5\times 10^{5}$。
题解:用$LCT$维护一条链上最深的不符合要求的元素。
看到这题我首先写了一个$O(nlog^{2}n)$的树剖,然后过了。
完。
我们令一个点的权值等于它所有儿子的原权值之和。
那么修改一个叶子影响的其实是从它到它上面第一个点权不是1/2的点。
于是我们就有一个$O(nlog^{2}n)$树剖的做法:
维护链上权值最小/最大值,每次从修改的叶子往上跳,跳到第一个不符合要求的链时二分终点位置。
但由于这是一道$LCT$练习题,我们可以考虑用$LCT$来维护这个东西。
只需要对于$Splay$的每个点维护它的子树内最深的不为1/2的点是哪个点即可。
由于$Splay$以深度为关键字我们甚至不需要记录原树上每个点的深度。
由于修改只有将1变成2,将2变成1,我们甚至不需要记录其他权值。
每次修改时将从根到$x$这条链上最深的不为1/2的点转到根,然后修改根的右子树即可。
时间复杂度$O(nlogn)$。
代码:
#include<bits/stdc++.h> #define maxn 500005 #define maxm 500005 #define inf 0x7fffffff #define ll long long #define ls c[u][0] #define rs c[u][1] #define debug(x) cerr<<#x<<": "<<x<<endl #define fgx cerr<<"--------------"<<endl #define dgx cerr<<"=============="<<endl using namespace std; int n,cc[maxn][3],f[maxn*3],val[maxn*3],lz[maxn]; int n1[maxn],n2[maxn],st[maxn],c[maxn][2]; inline int read(){ int x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } inline void dfs(int u){ for(int i=0;i<3;i++) if(cc[u][i]<=n) dfs(cc[u][i]),val[u]+=(val[cc[u][i]]>1); return; } inline bool nroot(int u){return c[f[u]][0]==u||c[f[u]][1]==u;} inline bool gc(int u){return c[f[u]][1]==u;} inline void pdr(int u,int v){val[u]+=v,lz[u]+=v,swap(n1[u],n2[u]);} inline void pd(int u){if(lz[u]) pdr(ls,lz[u]),pdr(rs,lz[u]),lz[u]=0;} inline void pu(int u){ if(n1[rs]) n1[u]=n1[rs]; else if(val[u]!=1) n1[u]=u; else n1[u]=n1[ls]; if(n2[rs]) n2[u]=n2[rs]; else if(val[u]!=2) n2[u]=u; else n2[u]=n2[ls]; } inline void rotate(int u){ int v=f[u],w=f[v],t1=gc(u),t2=gc(v),s=c[u][t1^1]; c[v][t1]=s; if(s)f[s]=v; if(nroot(v)) c[w][t2]=u;f[u]=w; c[u][t1^1]=v,f[v]=u; pu(v),pu(u),pu(w); } inline void splay(int u){ int p=0,v=u; st[++p]=v; while(nroot(v)) st[++p]=(v=f[v]); while(p) pd(st[p--]); for(v=f[u];nroot(u);rotate(u),v=f[u]) if(nroot(v)) rotate((gc(u)==gc(v))?v:u); } inline void access(int u){for(int v=0;u;u=f[v=u]) splay(u),rs=v,pu(u);} int main(){ n=read(); for(int u=1;u<=n;u++) for(int i=0;i<3;i++) f[cc[u][i]=read()]=u; for(int u=n+1;u<=3*n+1;u++) val[f[u]]+=(val[u]=read()); dfs(1); for(int u=1;u<=n;u++){ if(val[u]!=1) n1[u]=u; if(val[u]!=2) n2[u]=u; } int Q=read(); while(Q--){ int u=read(); val[u]^=1; if(val[u]){ u=f[u],access(u),splay(u); if(!n1[u]) pdr(u,1); else u=n1[u],splay(u),pdr(rs,1),val[u]++,pu(u); } else{ u=f[u],access(u),splay(u); if(!n2[u]) pdr(u,-1); else u=n2[u],splay(u),pdr(rs,-1),val[u]--,pu(u); } splay(1),printf("%d\n",(val[1]>1)); } return 0; }