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


    Solution

    ​ 因为要求路径上的字符重新排序后为回文串,也就是说出现次数为奇数的字符不会超过一个。我们给每个字符一个 (2^x) 形式的权值,那么合法路径异或和要么为 (0) ,要么为 (2^x) 的形式。

    ​ 设点 (x) 到根的异或和为 (D_x) ,由于是边权,x和y路径上的异或和可以用 (D_x~xor~D_y) 来表示。再用一个数组 (c) 来存储答案。其中 (c_i) 表示 (D_x=i)(x) 的最大深度。

    ​ 我们可以用 (dsu~on~tree) 来将复杂度优化到 (O(nlog~n)) ,因为 (dsu~on~tree) 可以利用轻重链剖分和启发式合并来更好的维护子树信息。

    代码

    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    
    using namespace std;
    const int N=500010,INF=1<<30;
    int n,c[1<<22],son[N],siz[N],dep[N];
    int head[N],nxt[N],D[N],ans[N];
    
    inline int read(){
        int x=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
        return x*f;
    }
    
    void dfs(int u){
        siz[u]=1;
        for(int i=head[u];i;i=nxt[i]){
            D[i]^=D[u];
            dep[i]=dep[u]+1;
            dfs(i);siz[u]+=siz[i];
            if(siz[i]>siz[son[u]]) son[u]=i;
        }
    }
    
    void init(int u){
        c[D[u]]=-INF;
        for(int i=head[u];i;i=nxt[i]) init(i);
    }
    
    int o;
    void up(int u){
        ans[o]=max(ans[o],dep[u]+c[D[u]]);
        for(int i=0;i<=21;i++) ans[o]=max(ans[o],dep[u]+c[1<<i^D[u]]);
        for(int i=head[u];i;i=nxt[i]) up(i);
    }
    
    void ins(int u){
        c[D[u]]=max(c[D[u]],dep[u]);
        for(int i=head[u];i;i=nxt[i]) ins(i);
    }
    
    //dsu on tree
    void work(int u){
        for(int i=head[u];i;i=nxt[i])
            if(i!=son[u]) work(i),init(i);
        if(son[u]) work(son[u]); o=u;
        for(int i=head[u];i;i=nxt[i])
            if(i!=son[u]) up(i),ins(i);
        c[D[u]]=max(c[D[u]],dep[u]);
        ans[u]=max(ans[u],dep[u]+c[D[u]]);
        for(int i=0;i<=21;i++) ans[u]=max(ans[u],dep[u]+c[1<<i^D[u]]);//枚举满足条件的y
        ans[u]-=dep[u]<<1;//x-y的距离=dep[y]+dep[x]-2*dep[x]
        for(int i=head[u];i;i=nxt[i]) ans[u]=max(ans[u],ans[i]);//在子树内比较
    }
    
    int main(){
        n=read();
        for(int i=0;i<(1<<22);i++) c[i]=-INF;
        for(int i=2,x;i<=n;i++){
            x=read();
            nxt[i]=head[x];head[x]=i;
            char c=getchar();
            while(c>'v'||c<'a') c=getchar();
            D[i]=1<<(c-'a');
        }
        dfs(1);work(1);
        for(int i=1;i<=n;i++) printf("%d ",ans[i]);
        return 0;
    }
    
  • 相关阅读:
    编译器优化 → C关键字volatile → memory破坏描述符zz
    Mybatis 控制台打出SqlLog的设置
    J2EE ssm框架服务启动项内存加载数据及读取。
    Oracle 同步表权限分配(同义词)
    iOS开发雕虫小技之傻瓜式定位神器超简单方式解决iOS后台定时定位
    Oracle分页查询SQL实现
    iOS新建项目基本配置
    DP之子序列问题
    图论之最小生成树
    基础数论算法
  • 原文地址:https://www.cnblogs.com/jasony/p/13634402.html
Copyright © 2020-2023  润新知