#Trie#洛谷 6018 [Ynoi2010] Fusion tree
题目
给定一棵树,树上每个节点都有点权,需要实现三种操作,
第一种是将与 \(x\) 相邻的所有节点点权加一,第二种是单点减小点权,
第三种是查询与 \(x\) 相邻的所有节点点权的异或和
分析
相邻实际上就是父节点和子节点,不妨将其拆开考虑,
需要解决单点查询单点修改的问题,考虑维护 \(n\) 棵 Trie 求子节点异或和
由低位到高位建树,实际上 \(w=(w_0 \oplus w_1)\times 2+[cnt_1\ is\ odd]\)
加一实际上就是进位的问题,那么 \(1,11,111,\dots\) 结尾的数都会变成零,
实际上就是 \(trie[p][0]\) 和 \(trie[p][1]\) 的交换
然后 \(1\) 为根节点而没有父节点,直接单独维护即可,时间复杂度 \(O(n\log a_i)\)
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
const int N=1234567; struct node{int y,next;}e[N];
int fat[N],as[N],et=1,n,Q,tot,rt[N],a[N],trie[N*20][2],c[N*20],ed[N*20],w[N*20],fa[N*20];
int iut(){
int ans=0,f=1; char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans*f;
}
void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
void dfs(int x,int fa){
fat[x]=fa;
for (int i=as[x];i;i=e[i].next)
if (e[i].y!=fa) dfs(e[i].y,x);
}
void update(int rt,int x,int i,int opt){
if (opt==-1){
--c[ed[i]];
for (int p=ed[i];fa[p];p=fa[p],--c[p])
w[fa[p]]=(w[trie[fa[p]][0]]^w[trie[fa[p]][1]])<<1|(c[trie[fa[p]][1]]&1);
ed[i]=0;
}else{
for (int j=0;j<20;++j){
int z=x&1; x>>=1;
if (!trie[rt][z]) trie[rt][z]=++tot;
fa[trie[rt][z]]=rt,rt=trie[rt][z];
}
++c[ed[i]=rt];
for (int p=ed[i];fa[p];p=fa[p],++c[p])
w[fa[p]]=(w[trie[fa[p]][0]]^w[trie[fa[p]][1]])<<1|(c[trie[fa[p]][1]]&1);
}
}
void plusone(int rt){
swap(trie[rt][0],trie[rt][1]);
if (trie[rt][0]) plusone(trie[rt][0]);
w[rt]=(w[trie[rt][0]]^w[trie[rt][1]])<<1|(c[trie[rt][1]]&1);
}
int query(int x){
int ans=0;
for (int p=ed[x];fa[p];p=fa[p])
if (trie[fa[p]][1]==p) ans=ans<<1|1;
else ans<<=1;
return ans;
}
int main(){
n=iut(),Q=iut();
for (int i=1;i<n;++i){
int x=iut(),y=iut();
e[++et]=(node){y,as[x]},as[x]=et;
e[++et]=(node){x,as[y]},as[y]=et;
}
dfs(1,0),tot=n;
for (int i=1;i<=n;++i) rt[i]=i;
for (int i=1;i<=n;++i){
a[i]=iut();
if (fat[i]) update(rt[fat[i]],a[i],i,1);
}
for (int i=1;i<=Q;++i)
switch (iut()){
case 1:{
int x=iut();
if (fat[x]==1) ++a[1];
else if (fat[fat[x]]){
int z=query(fat[x]);
update(rt[fat[fat[x]]],z,fat[x],-1);
update(rt[fat[fat[x]]],z+1,fat[x],1);
}
plusone(rt[x]);
break;
}
case 2:{
int x=iut(),y=iut();
if (x==1) a[x]-=y;
else{
int z=query(x);
update(rt[fat[x]],z,x,-1);
update(rt[fat[x]],z-y,x,1);
}
break;
}
case 3:{
int x=iut(),z=w[rt[x]];
if (fat[fat[x]]) z^=query(fat[x]);
else if (fat[x]==1) z^=a[1];
print(z),putchar(10);
break;
}
}
return 0;
}