[CF741D]Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

luogu

Description

一棵以\(1\)号点为根的有根树,每条边上有一个小写字母\(a~v\)。定义一条路经是好的,当且仅当这条路径上经过的所有小写字母重排后可以构成回文串。
求以每个点为根的子树中最长的好的路径。

sol

算法发明者自己出的题,可以去他的blog里面看看。

首先,对于一条字母是\(ch\)的边,定义其权值为\(2^{ch-'a'}\)
这样一条路经是好的就当且仅当这条路径的异或和二进制位中的\(1\)的个数不超过\(1\)
在处理以某一点为根的子树时,开桶,记\(f[i]\)表示到根路径异或和为\(i\)的点的最大深度,可以类似点分的方法计算答案并更新桶。
现在问题的瓶颈在于:每棵子树需要分别处理,把结果全部保存下来空间开不下,而每次重新计算一遍时间上吃不消。
考虑\(dsu\ on \ tree\)
先递归处理轻儿子,删除轻儿子的贡献,递归处理重儿子,保存其贡献,再把轻儿子全部再算一遍。
复杂度是\(O(n\log n)\)的。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int gi(){
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
const int N = 5e5+5;
int n,nxt[N],val[N],head[N],dfn[N],low[N],tim,id[N],dep[N],sz[N],son[N],Xor[N],f[1<<22],ans[N];
void dfs1(int u){
    id[dfn[u]=++tim]=u;sz[u]=1;
    for (int v=head[u];v;v=nxt[v]){
        dep[v]=dep[u]+1;Xor[v]=Xor[u]^val[v];
        dfs1(v);sz[u]+=sz[v];
        if (sz[v]>sz[son[u]]) son[u]=v;
    }
    low[u]=tim;
}
void dfs(int u,int keep){
    for (int v=head[u];v;v=nxt[v])
        if (v!=son[u]) dfs(v,0),ans[u]=max(ans[u],ans[v]);
    if (son[u]) dfs(son[u],1),ans[u]=max(ans[u],ans[son[u]]);

    if (f[Xor[u]]) ans[u]=max(ans[u],f[Xor[u]]-dep[u]);
    for (int i=0;i<22;++i)
        if (f[Xor[u]^(1<<i)]) ans[u]=max(ans[u],f[Xor[u]^(1<<i)]-dep[u]);
    f[Xor[u]]=max(f[Xor[u]],dep[u]);

    for (int v=head[u];v;v=nxt[v])
        if (v!=son[u]){
            for (int i=dfn[v];i<=low[v];++i){
                if (f[Xor[id[i]]]) ans[u]=max(ans[u],f[Xor[id[i]]]+dep[id[i]]-(dep[u]<<1));
                for (int j=0;j<22;++j)
                    if (f[Xor[id[i]]^(1<<j)])
                        ans[u]=max(ans[u],f[Xor[id[i]]^(1<<j)]+dep[id[i]]-(dep[u]<<1));
            }
            for (int i=dfn[v];i<=low[v];++i){
                f[Xor[id[i]]]=max(f[Xor[id[i]]],dep[id[i]]);
            }
        }
    if (!keep) for (int i=dfn[u];i<=low[u];++i) f[Xor[id[i]]]=0;
}
int main(){
    n=gi();
    for (int i=2;i<=n;++i){
        int f=gi();char ch=getchar();
        nxt[i]=head[f];val[i]=1<<ch-'a';head[f]=i;
    }
    dep[1]=1;dfs1(1);dfs(1,0);
    for (int i=1;i<=n;++i) printf("%d ",ans[i]);
    puts("");return 0;
}

猜你喜欢

转载自www.cnblogs.com/zhoushuyu/p/9116039.html