LGP6018 [Ynoi 2010] Fusion Tree 学习笔记
LGP6018 [Ynoi 2010] Fusion Tree 学习笔记
前言
魔法森林里有一颗大树,下面经常有小孩召开法。
麦杰斯住在大树顶端,有一天他想改造一下大树,方便他巨大多喝水之后可以垃圾分类矿泉水瓶。
关于Ynoi为什么掺进了龚诗等迫真中华例区要素,我暂且蒙在古里。
题意简述
给定一棵 \(n\) 个结点的无根树。每个结点有个点权 \(a_i\)。需要支持三种操作:
- 将 \(u\) 的所有邻接点的点权加 \(1\)。
- 将 \(a_u\) 减去 \(v\)。
- 询问 \(u\) 的所有邻接点的点权的异或和。
\(n,m,a_i\le 5\times 10^5\)。
做法解析
根存最低位的01Trie的套路题。
首先我们不会做无根树,所以我们设置一个根,这样“维护邻接点”就转化为了“维护父亲”和“维护儿子们”。
然后查异或和想到01Trie,看到范围加 \(1\) 想到根存最低位的那种01Trie。
那么这道题就很简单了,我们对每个结点维护一棵01Trie,里面存放自己的所有儿子的数值。对于 \(u\) 临接点加的操作,我们先找到 \(u\) 的父亲暴力删掉 \(u\) 原数值,更新数值后再加回来;然后对于 \(u\) 的那棵01Trie,我们来考察全局加一会发生什么。我们发现,原来最低位为 \(0\) 的现在最低位会变成 \(1\),反之亦然,所以我们把Trie的两个儿子对调;我们又发现对于那些进了位的数,如果其原来第二位是 \(1\),那还会再进一位,所以我们就从根不断重复这个过程:交换两个儿子后,沿着当前的 \(0\) 儿子方向递归这个过程。
单点减显然,也是暴力改。邻接异或和呢?我们维护01Trie上每个结点被经过的次数,如果某位出现奇数次这位就取到 \(1\)。这也是很好动态维护的。最后再异或上自己父亲的值就OK。
然后这题就做完了。
代码实现
#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=5e5+5,MaxVb=18;
int N,M,X,Y,Opt,ans,A[MaxN];
vector<int> Tr[MaxN];
void addudge(int u,int v){
Tr[u].push_back(v);
Tr[v].push_back(u);
}
int tfa[MaxN],tag[MaxN];
void dfs(int u,int f){tfa[u]=f;for(int v : Tr[u])if(v!=f)dfs(v,u);}
struct BilexiTree{
int rt[MaxN],ch[MaxN<<5][2],w[MaxN<<5],xorv[MaxN<<5],ncnt;
void maintain(int u){
w[u]=xorv[u]=0;
if(ch[u][0])w[u]+=w[ch[u][0]],xorv[u]^=(xorv[ch[u][0]]<<1);
if(ch[u][1])w[u]+=w[ch[u][1]],xorv[u]^=(xorv[ch[u][1]]<<1)|(w[ch[u][1]]&1);
}
void newnode(int &u){u=++ncnt;}
void inse(int &u,int x,int d){
if(!u)newnode(u);if(d>MaxVb){w[u]++;return;}
inse(ch[u][x&1],x>>1,d+1);maintain(u);
}
void init(int n){
for(int i=1;i<=n;i++)if(tfa[i])inse(rt[tfa[i]],A[i],0);
}
void dele(int u,int x,int d){
if(d>MaxVb){w[u]--;return;}
dele(ch[u][x&1],x>>1,d+1),maintain(u);
}
void swapit(int u){
swap(ch[u][0],ch[u][1]);
if(ch[u][0])swapit(ch[u][0]);
maintain(u);
}
int aget(int u){return A[u]+tag[tfa[u]];}
void rincr(int u){
tag[u]++;swapit(rt[u]);int &f=tfa[u];if(!f)return;
int &g=tfa[f];
if(g)dele(rt[g],aget(f),0);
A[f]++;
if(g)inse(rt[g],aget(f),0);
}
void sdecr(int u,int x){
int &f=tfa[u];
if(f)dele(rt[f],aget(u),0);
A[u]-=x;
if(f)inse(rt[f],aget(u),0);
}
int getans(int u){return xorv[rt[u]]^aget(tfa[u]);}
}BlT;
int main(){
readis(N,M);
for(int i=1;i<N;i++)readis(X,Y),addudge(X,Y);
dfs(1,0);for(int i=1;i<=N;i++)readi(A[i]);
BlT.init(N);for(int i=1;i<=M;i++){
readis(Opt,X);
if(Opt==1)BlT.rincr(X);
if(Opt==2)readi(Y),BlT.sdecr(X,Y);
if(Opt==3)ans=BlT.getans(X),writil(ans);
}
return 0;
}
浙公网安备 33010602011771号