• Codeforces 741.D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths


    D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths
    time limit per test
    3 seconds
    memory limit per test
    256 megabytes
    input
    standard input
    output
    standard output

    Just in case somebody missed it: we have wonderful girls in Arpa’s land.

    Arpa has a rooted tree (connected acyclic graph) consisting of n vertices. The vertices are numbered 1 through n, the vertex 1 is the root. There is a letter written on each edge of this tree. Mehrdad is a fan of Dokhtar-kosh things. He call a string Dokhtar-kosh, if we can shuffle the characters in string such that it becomes palindrome.

    He asks Arpa, for each vertex v, what is the length of the longest simple path in subtree of v that form a Dokhtar-kosh string.

    Input

    The first line contains integer n (1  ≤  n  ≤  5·105) — the number of vertices in the tree.

    (n  -  1) lines follow, the i-th of them contain an integer pi + 1 and a letter ci + 1 (1  ≤  pi + 1  ≤  ici + 1 is lowercase English letter, between a and v, inclusively), that mean that there is an edge between nodes pi + 1 and i + 1 and there is a letter ci + 1 written on this edge.

    Output

    Print n integers. The i-th of them should be the length of the longest simple path in subtree of the i-th vertex that form a Dokhtar-kosh string.

    Examples
    input
    4
    1 s
    2 a
    3 s
    output
    3 1 1 0 
    input
    5
    1 a
    2 h
    1 a
    4 h
    output
    4 1 0 1 0 
    题目大意:一棵树,每条边上有一个字符,问每个点的子树中最长的合法路径长度。所谓的合法路径长度就是给路径中的所有字符重新组合后可以是回文串。
    分析:显然的dsu on the tree,不带修改操作,又只涉及到子树查询,只是细节比较麻烦.
       满足要求的路径就是至多只有一个出现奇数次数字符,因为字符只可能是a ~ v,共22个字符,所以可以用二进制数存状态,0/1表示出现了偶数次/奇数次. s[i]表示1到i号点的路径的状态. f[i]表示状态为i的点的最深深度,h[i]表示i号点的深度.
       考虑路径有哪些情况:不经过当前根节点的路径和经过当前根节点的路径,不经过当前根节点的路径在递归处理子节点的时候可以顺便处理完,经过当前根节点的有两种:一端恰好是根节点;两端在不同的子树内.前一种要特殊判断一下,后面一种的处理将修改和查询的顺序变一下:先查询,后修改.那么就能避免统计到同一子树内的答案.因为同一子树内的答案已经包含在前面的讨论的情况中了:不经过根节点和只有一端是根节点.
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    
    const ll maxn = 500010;
    
    int head[maxn],nextt[maxn * 2],to[maxn * 2],tot = 1,a[maxn],n,s[maxn],h[maxn];
    int sizee[maxn],son[maxn],ans[maxn],vis[maxn],f[maxn * 20],inf;
    
    void add(int x,int y)
    {
        to[tot] = y;
        nextt[tot] = head[x];
        head[x] = tot++;
    }
    
    void dfs1(int u,int fa)
    {
        h[u] = h[fa] + 1;
        if (u != 1)
            s[u] = s[fa] ^ (1 << a[u]);
        sizee[u] = 1;
        for (int i = head[u]; i; i = nextt[i])
        {
            int v = to[i];
            if (v == fa)
                continue;
            dfs1(v,u);
            sizee[u] += sizee[v];
            if(sizee[v] > sizee[son[u]])
                son[u] = v;
        }
    }
    
    void cal(int u,int fa,int root)
    {
        ans[root] = max(ans[root],h[u] + f[s[u]] - 2 * h[root]);
        if ((s[u] ^ s[root]) == 0)
            ans[root] = max(ans[root],h[u] - h[root]);
        for (int i = 0; i < 22; i++)
        {
            int temp = s[u] ^ (1 << i);
            ans[root] = max(ans[root],h[u] + f[temp] - 2 * h[root]);
            if ((s[u] ^ s[root]) == (1 << i))
                ans[root] = max(ans[root],h[u] - h[root]);
        }
        for (int i = head[u];i;i = nextt[i])
        {
            int v = to[i];
            if (v == fa)
                continue;
            cal(v,u,root);
        }
    }
    
    void update(int u,int fa,int flag)
    {
        if (flag)
            f[s[u]] = max(f[s[u]],h[u]);
        else
            f[s[u]] = inf;
        for (int i = head[u];i;i = nextt[i])
        {
            int v = to[i];
            if (v == fa)
                continue;
            update(v,u,flag);
        }
    }
    
    void dfs2(int u,int fa,int flag)
    {
        for (int i = head[u];i;i = nextt[i])
        {
            int v = to[i];
            if (v == fa || v == son[u])
                continue;
            dfs2(v,u,0);
        }
        if (son[u])
            dfs2(son[u],u,1);
        int temp = s[u];
            ans[u] = max(ans[u],f[temp] - h[u]);
        for (int i = 0; i < 22; i++)
        {
            temp = s[u] ^ (1 << i);
            ans[u] = max(ans[u],f[temp] - h[u]);
        }
        for (int i = head[u];i;i = nextt[i])
        {
            int v = to[i];
            if (v == fa || v == son[u])
                continue;
            cal(v,u,u);
            update(v,u,1);
        }
        if (!flag)
        {
            for (int i = head[u];i;i = nextt[i])
            {
                int v = to[i];
                if (v == fa)
                    continue;
                update(v,u,0);
            }
            f[s[u]] = inf;
        }
        else
            f[s[u]] = max(f[s[u]],h[u]);
    }
    
    void dfs3(int u,int fa)
    {
        for (int i = head[u];i;i = nextt[i])
        {
            int v = to[i];
            if (v == fa)
                continue;
            dfs3(v,u);
            ans[u] = max(ans[u],ans[v]);
        }
    }
    
    int main()
    {
        memset(f,128,sizeof(f));
        inf = f[0];
        scanf("%d",&n);
        for (int i = 2; i <= n; i++)
        {
            int fa;
            char ch[2];
            scanf("%d",&fa);
            scanf("%s",ch);
            a[i] = ch[0] - 'a';
            add(fa,i);
            add(i,fa);
        }
        dfs1(1,0);
        dfs2(1,0,1);
        dfs3(1,0);
        for (int i = 1; i <= n; i++)
            printf("%d ",ans[i]);
        printf("
    ");
    
        return 0;
    }


       
  • 相关阅读:
    CC3000 SmartConfig
    谈谈几个月以来开发android蓝牙4.0 BLE低功耗应用的感受
    CC3000 SPI接口编程介绍
    cc3000+LM3S9B96
    CC3000 主机驱动API介绍
    Wi-FiR CC3000 模块
    修改远程桌面连接端口及修改端口号后如何连接!
    电脑网线/水晶头的连接方法(A类,B类)
    快速切换IP的批处理!
    IE打开报错,提示该内存不能为read的解决办法!
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8450439.html
Copyright © 2020-2023  润新知