题目
Sol
\(dsu \ on \ tree\)的好题。
注意到字符集只有\(a\)到\(v\),这提示我们用状压来做。
设\(w[u]\)为根节点到\(u\)节点路径上的字符的奇偶情况,\(f[S]\)从\(u\)节点出发往下走,使得路径状态为\(S\)的最大深度。
先把\(u\)所有儿子的答案都计算好。
然后直接继承重儿子的\(f\)数组,并更新一次答案。
然后对于\(u\)每一个轻儿子子树内的每一个点,先更新答案,再更新\(f\)。
更新答案:枚举每一种可能的状态\(T(2^i||0,i\in [0,21])\),设当前枚举到的点为\(v\),则此时的答案\(ans[u]\)可以为\(dep[v]+f[T\ xor\ w[v]]-dep[u]-dep[u]\)
code
inline void dfs1(int st,int fa){
sz[st]=1,dep[st]=dep[fa]+1,dfn[++tct]=st,pos[st]=tct,w[st]=w[fa]^(1<<val[st]);
for(int i=0;i<(int)e[st].size();i++){
int ed=e[st][i];
if(ed==fa) continue;
dfs1(ed,st);
sz[st]+=sz[ed];
if(sz[ed]>sz[son[st]]) son[st]=ed;
}
return;
}
inline void dfs2(int st,int fa){
for(int i=0;i<(int)e[st].size();i++){
int ed=e[st][i];
if(ed==fa||ed==son[st]) continue;
dfs2(ed,st);
for(int j=pos[ed];j<=pos[ed]+sz[ed]-1;j++) f[w[dfn[j]]]=0;
ans[st]=max(ans[st],ans[ed]);
}
if(son[st]) dfs2(son[st],st),ans[st]=max(ans[st],ans[son[st]]);
if(f[w[st]]) ans[st]=max(ans[st],f[w[st]]-dep[st]);
for(int i=0;i<22;i++) if(f[(1<<i)^w[st]]) ans[st]=max(ans[st],f[w[st]^(1<<i)]-dep[st]);
f[w[st]]=max(f[w[st]],dep[st]);
for(int i=0;i<(int)e[st].size();i++){
int ed=e[st][i];
if(ed==fa||ed==son[st]) continue;
for(int j=pos[ed];j<=pos[ed]+sz[ed]-1;j++){
int W=w[dfn[j]],ED=dfn[j];
if(f[W]) ans[st]=max(ans[st],f[W]+dep[ED]-dep[st]-dep[st]);
for(int k=0;k<22;k++) if(f[W^(1<<k)]) ans[st]=max(ans[st],f[(1<<k)^W]+dep[ED]-dep[st]-dep[st]);
}
for(int j=pos[ed];j<=pos[ed]+sz[ed]-1;j++) f[w[dfn[j]]]=max(f[w[dfn[j]]],dep[dfn[j]]);
}
return;
}