$CF741D$题解

这是一道好题……

关于这篇文章我为什么不和\(dsu\) \(on\) \(tree\)放一起,因为这题太好了,单独拿出来会好些

这是可爱的链接

先大致扫一眼题意,发现一条路径满足条件,当且仅当上面至多有一种字母出现次数为奇数次,总共有\(22\)种,因此我们可以考虑状压,\(0\)表示一个字母出现偶数次,\(1\)表示出现奇数次,用异或处理即可。

再看一下题目,很像一道点分治的题(真的,树上路径你告诉我不像?)但是这道题是一颗定根树,树根为\(1\)

显然不能点分治,但是点分治的思路可以借鉴一下,考虑树上启发式合并\(dsu\) \(on\) \(tree\)

即在做答案时用点分治的方式做(一条路径可行的情况只有\(23\)种),维护信息时用树上启发式合并的方法取维护。

我们维护一个\(f[x]\)表示从根节点出发路径异或之后的值为\(x\)的最大深度。

这一题因为用到了点分治的思路,所以相当于我们做答案时是先算了\(x\)的每个子树的答案,在考虑所有过\(x\)的路径,因此我们在\(dsu\) \(on\) \(tree\)上做答案时递归需要保留\(x\)(但这种情况我还没改出来,有知道的怎么改的跟我讲一下好吗?)

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int f=1,w=0;char x=0;
    while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();}
    while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();}
    return w*f;
}
const int N=500010;
int num_edge,n,Tim,Id[N];
int head[N],Dep[N],Xor[N],f[1<<22],End[N];
int Vis[N],Siz[N],Max[N],ans[N],Dfn[N];
struct Edge{int next,to,dis;} edge[N];
inline void Add(int from,int to,int dis)
{
    edge[++num_edge].next=head[from];
    edge[num_edge].dis=dis;
    edge[num_edge].to=to;
    head[from]=num_edge;
}
inline void Dfs_For_Pre(int pos,int fth,int dis)
{
    Dfn[pos]=++Tim,Id[Dfn[pos]]=pos;Siz[pos]=1;
    Dep[pos]=Dep[fth]+1;Xor[pos]=Xor[fth]^dis;
    for(int i=head[pos];i;i=edge[i].next)
    {
        Dfs_For_Pre(edge[i].to,pos,edge[i].dis);
        Siz[pos]+=Siz[edge[i].to];
        if(Siz[Max[pos]]<Siz[edge[i].to]) Max[pos]=edge[i].to;
    }
    End[pos]=Tim;
}
/*inline void Update(int pos,int Anc)
{
    if(f[Xor[pos]]) ans[Anc]=max(ans[Anc],f[Xor[pos]]+Dep[pos]-(Dep[Anc]<<1));
    for(int j=0;j<22;j++)
        if(f[Xor[pos]^(1<<j)])
            ans[Anc]=max(ans[Anc],f[Xor[pos]^(1<<j)]+Dep[pos]-(Dep[Anc]<<1));
    for(int i=head[pos];i;i=edge[i].next)
        if(!Vis[edge[i].to]) Update(edge[i].to,Anc);
}
inline void Cancel(int pos)
{
    for(int i=head[pos];i;i=edge[i].next)
        f[Xor[edge[i].to]]=0,Cancel(edge[i].to);
}
inline void Change(int pos)
{
    for(int i=head[pos];i;i=edge[i].next)
        f[Xor[edge[i].to]]=max(f[Xor[edge[i].to]],Dep[edge[i].to]),Change(edge[i].to);
}
inline void Dsu_On_Tree(int pos,int Jud)
{
    for(int i=head[pos];i;i=edge[i].next)
        if(edge[i].to!=Max[pos])
            Dsu_On_Tree(edge[i].to,0),ans[pos]=max(ans[pos],ans[edge[i].to]);
    if(Max[pos]) Dsu_On_Tree(Max[pos],1),ans[pos]=max(ans[pos],ans[Max[pos]]),Vis[Max[pos]]=1;
    
    if(f[Xor[pos]]) ans[pos]=max(ans[pos],f[Xor[pos]]-Dep[pos]);
    for(int i=0;i<22;i++)
        if(f[Xor[pos]^(1<<i)]) ans[pos]=max(ans[pos],f[Xor[pos]^(1<<i)]-Dep[pos]);
    f[Xor[pos]]=max(f[Xor[pos]],Dep[pos]);
    
    for(int i=head[pos];i;i=edge[i].next)
        if(!Vis[edge[i].to]) Update(edge[i].to,pos),Change(edge[i].to);
    Vis[Max[pos]]=0;if(!Jud) f[Xor[pos]]=0,Cancel(pos);
}
*/
inline void Dsu_On_Tree(int pos,int Jud)
{
    for(int i=head[pos];i;i=edge[i].next)
        if(edge[i].to!=Max[pos])
            Dsu_On_Tree(edge[i].to,0),ans[pos]=max(ans[pos],ans[edge[i].to]);
    if(Max[pos]) Dsu_On_Tree(Max[pos],1),ans[pos]=max(ans[pos],ans[Max[pos]]);
    
    if(f[Xor[pos]]) ans[pos]=max(ans[pos],f[Xor[pos]]-Dep[pos]);
    for(int i=0;i<22;i++)
        if(f[Xor[pos]^(1<<i)]) ans[pos]=max(ans[pos],f[Xor[pos]^(1<<i)]-Dep[pos]);
    f[Xor[pos]]=max(f[Xor[pos]],Dep[pos]);

    for(int i=head[pos];i;i=edge[i].next)
        if(edge[i].to!=Max[pos])
        {
            for(int j=Dfn[edge[i].to];j<=End[edge[i].to];j++)
            {
                if(f[Xor[Id[j]]]) ans[pos]=max(ans[pos],f[Xor[Id[j]]]+Dep[Id[j]]-(Dep[pos]<<1));
                for(int k=0;k<22;k++)
                    if(f[Xor[Id[j]]^(1<<k)]) ans[pos]=max(ans[pos],f[Xor[Id[j]]^(1<<k)]+Dep[Id[j]]-(Dep[pos]<<1));
            }
            for(int j=Dfn[edge[i].to];j<=End[edge[i].to];j++)
                f[Xor[Id[j]]]=max(f[Xor[Id[j]]],Dep[Id[j]]);
        }
    if(!Jud) for(int j=Dfn[pos];j<=End[pos];j++) f[Xor[Id[j]]]=0;
}
int main(){
#ifndef ONLINE_JUDGE
    //freopen("A.in","r",stdin);//Ans=3 1 1 0 
    freopen("B.in","r",stdin);//Ans=4 1 0 1 0 
#endif
    char c;n=read();
    for(int i=2,x;i<=n;i++)
        x=read(),c=getchar(),Add(x,i,1<<(c-'a'));
    Dfs_For_Pre(1,0,0);Dsu_On_Tree(1,0);
    for(int i=1;i<=n;i++) printf("%d ",ans[i]);
}

猜你喜欢

转载自www.cnblogs.com/wo-shi-zhen-de-cai/p/11535026.html