• 【CodeForces】914 E. Palindromes in a Tree 点分治


    【题目】E. Palindromes in a Tree

    【题意】给定一棵树,每个点都有一个a~t的字符,一条路径回文定义为路径上的字符存在一个排列构成回文串,求经过每个点的回文路径数。n<=2*10^5。

    【算法】点分治

    【题解】状压20位的二进制表示一条路径的字符状态,点分治过程中维护扫描过的路径只须维护状态桶数组,t[i]表示前面状态为i的路径条数。

    合并:考虑当前状态为j,要使合并的状态满足条件即i^j=1<<k(0<=k<20)或i^j=0,移项得i=j^(1<<k)或i=j,所以路径数是Σ t [ j^(1<<k) ]+t[j]。

    统计每个点:对于当前要处理的重心x,先遍历所有子树得到整个t[]数组,然后对每个子树先删除其在桶里的状态,然后扫一遍贡献子树中每个点,最后将子树的状态加回桶中。

    这样可以做到每条路径都贡献到每个点,要特殊处理重心的贡献。

    复杂度O(n log n)。

    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int maxn=200010,maxN=2000010;
    int tot,first[maxn],sz[maxn],vis[maxn],sum,root,a[maxn],u,v,n;
    ll ans[maxn],t[maxN];
    struct edge{int v,from;}e[maxn*2];
    
    void insert(int u,int v){tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;}
    void getroot(int x,int fa){
        sz[x]=1;
        bool ok=1;
        for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa&&!vis[e[i].v]){
            getroot(e[i].v,x);
            sz[x]+=sz[e[i].v];
            if(sz[e[i].v]>sum/2)ok=0;
        }
        if(ok&&sz[x]>=sum/2)root=x;
    }
    void dfs(int x,int fa,int p,int s){
        t[s^=(1<<a[x])]+=p;
        for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa&&!vis[e[i].v])dfs(e[i].v,x,p,s);
    }
    ll calc(int x,int fa,int s){
        s^=(1<<a[x]);ll num=t[s];
        for(int i=0;i<20;i++)num+=t[s^(1<<i)];
        for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa&&!vis[e[i].v])num+=calc(e[i].v,x,s);
        ans[x]+=num;
        return num;
    }
    void solve(int x,int s){
        vis[x]=1;
        dfs(x,0,1,0);
        ll num=t[0];
        for(int i=0;i<20;i++)num+=t[1<<i];
        for(int i=first[x];i;i=e[i].from)if(!vis[e[i].v]){
            dfs(e[i].v,x,-1,1<<a[x]);
            num+=calc(e[i].v,x,0);
            dfs(e[i].v,x,1,1<<a[x]);
        }
        ans[x]+=num/2;
        dfs(x,0,-1,0);
        for(int i=first[x];i;i=e[i].from)if(!vis[e[i].v]){
            if(sz[e[i].v]>sz[x])sum=s-sz[x];else sum=sz[e[i].v];
            getroot(e[i].v,x);
            solve(root,sum);
        }
    }
    char s[maxn];
    int main(){
        scanf("%d",&n);
        for(int i=1;i<n;i++){
            scanf("%d%d",&u,&v);
            insert(u,v);insert(v,u);
        }
        scanf("%s",s+1);
        for(int i=1;i<=n;i++)a[i]=s[i]-'a';
        sum=n;
        getroot(1,0);
        solve(root,sum);
        for(int i=1;i<=n;i++)printf("%lld ",ans[i]+1);
        return 0;
    }
    View Code
  • 相关阅读:
    MCPD 70536题目 自定义打印参数
    《ERP从内部集成起步》读书笔记——第5章 MRP系统的时间概念 5.1 时间三要素 5.1.2 时段
    Jquey拖拽控件Draggable用法
    MCPD 70536题目 反射
    MCPD 70536题目 非托管资源 释放
    VS2008创建Silverlight项目时出错解决方法
    程序猿去旅行
    EntityFramework5.0 数据迁移笔记解决模型变化重建数据库的问题
    完美生活
    一直很安静
  • 原文地址:https://www.cnblogs.com/onioncyc/p/8334111.html
Copyright © 2020-2023  润新知