zoukankan      html  css  js  c++  java
  • Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths CodeForces

    题意:

      给出一棵 (n) 个点的树,每条边上有一个字母((a o v),共 (22) 个),对于每一个子树,询问其中最长的,满足:路径上的字符集可以重组成回文字符串的路径的长度。
    数据范围:(1  ≤  n  ≤  5·10^5)

    分析:

      (dsu;on;tree) 可用于解决不带修改的树上问题。
      其大致过程为:对于每个点 (v),先遍历其轻儿子所在的子树,遍历完成后,清除其影响。最后遍历重儿子,保留影响。然后,把点 (v)和所有轻儿子的影响加到重儿子上(相当于再一次遍历以点 (v) 为根的子树,但没有遍历重儿子所在的子树)。相对于暴力 (O(n^2)) 的做法,它第二次遍历的点只有轻儿子。可以证明,其复杂度可以优化到 (O(nlogn)),和分块一样是优美的暴力。
      本题的巧妙之处在于异或的运用和状态压缩。每个字母赋予一个 (2) 进制位,预处理出每个点到根结点的异或值。对于一条满足条件的路径,所有字母异或之后的结果为 (0)(2^x) 的形式。对于路径的连个端点 (u)(v),两者的 (lca) 到根节点的路径重复了两次,所以可以抵消。然后对于点 (v) 所在子树的满足条件的最长路径,有两种情况。
    1.点 (v) 在路径上。
    2.点 (v) 不在路径上,那么只要求出儿子的最大值即可。
    本题所说的影响为每种异或值所在的最大深度。
    注意初始化时,要赋 (-inf),而不能赋 (0)

    代码:

    #include <bits/stdc++.h>
    #define pb push_back
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    const int N=5e5+5;
    const int maxn=1e7;
    int son[N],sz[N],depth[N],xr[N],ans[N];
    int d[maxn];
    vector<int>G[N];
    void read(int &x)
    {
        x=0;
        int f=1;
        char ch=getchar();
        while(!isdigit(ch))
        {
            if(ch=='-')
                f=-1;
            ch=getchar();
        }
        while(isdigit(ch))
        {
            x=(x<<3)+(x<<1)+ch-'0';
            ch=getchar();
        }
        x*=f;
    }
    void dfs1(int v,int d)
    {
        sz[v]=1;
        depth[v]=d;
        son[v]=0;
        for(int i=0;i<G[v].size();i++)
        {
            int u=G[v][i];
            xr[u]^=xr[v];
            dfs1(u,d+1);
            sz[v]+=sz[u];
            if(sz[u]>sz[son[v]])
                son[v]=u;
        }
    }
    void add(int v)
    {
        d[xr[v]]=max(d[xr[v]],depth[v]);
        for(int i=0;i<G[v].size();i++)
            add(G[v][i]);
    }
    void an(int v,int tp)
    {
        ans[tp]=max(ans[tp],depth[v]+d[xr[v]]);
        for(int i=0;i<22;i++)
            ans[tp]=max(ans[tp],depth[v]+d[(1<<i)^xr[v]]);
        for(int i=0;i<G[v].size();i++)
            an(G[v][i],tp);
    }
    void del(int v)
    {
        d[xr[v]]=-inf;
        for(int i=0;i<G[v].size();i++)
            del(G[v][i]);
    }
    void dfs2(int v,bool f)
    {
        for(int i=0;i<G[v].size();i++)
        {
            int u=G[v][i];
            if(u==son[v]) continue;
            dfs2(u,false);
        }
        if(son[v])
            dfs2(son[v],true);
        for(int i=0;i<G[v].size();i++)
        {
            if(G[v][i]!=son[v])
                an(G[v][i],v),add(G[v][i]);//为了保证路径一定过点v
        }
        d[xr[v]]=max(d[xr[v]],depth[v]);
        ans[v]=max(ans[v],d[xr[v]]+depth[v]);//cout<<v<<" = "<<ans[v]<<endl;
        for(int i=0;i<22;i++)
            ans[v]=max(ans[v],depth[v]+d[(1<<i)^xr[v]]);//
        ans[v]-=(depth[v]*2);//减去重复的部分
        for(int i=0;i<G[v].size();i++)//点v不在路径中,从儿子节点中找
            ans[v]=max(ans[v],ans[G[v][i]]);
        if(!f)//轻儿子要清空
            del(v);
    }
    int main()
    {
        int n,u;
        char op[5];
        read(n);
        fill(d+1,d+(1<<22),-inf);//注意初始化为-inf
        for(int i=2;i<=n;i++)
        {
            read(u);
            scanf("%s",op);
            G[u].pb(i);
            xr[i]^=(1<<(op[0]-'a'));//每个字母分配二进制的一位
        }
        dfs1(1,0);//for(int i=1;i<=n;i++) cout<<" son="<<son[i];cout<<endl;
        dfs2(1,0);
        for(int i=1;i<=n;i++)
            printf("%d%c",ans[i],i==n?'
    ':' ');
        return 0;
    }
    
    
  • 相关阅读:
    css(完)
    HTML学习(完)
    leetcode学习03
    多线程详解2(完)
    windows7 64位下安装apache和php
    一个js,记录方便查询。
    用了锚的时候,有的层被覆盖了。
    日,在ie10下面hover里不能控制table
    在实现tab的时候,margin-bottom:-1px无效的问题
    javascript中,在一个类里attache的event事件中,如果调用类的成员变量和方法
  • 原文地址:https://www.cnblogs.com/1024-xzx/p/12601056.html
Copyright © 2011-2022 走看看