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

    Link
    树上启发式合并(静态链分治)模板题。
    首先一个串能重排形成是回文串当且仅当其字符数量最多有一个为奇数。
    因此我们只关心路径上某个字符的奇偶性。
    所以我们对字符集状压,(0)表示偶,(1)表示奇。
    (dis_u)(1)(u)的路径上的字符集。
    那么对于点对(u,v),其路径上的字符集为(dis_uoplus dis_v)
    一条路径的字符集(S)合法当且仅当(S=2^i(iin[0,21])igvee S=0)
    我们先考虑暴力的做法:
    开一个桶(t_i)记录(dis_u)(i)的点中(dep)最大的点(u)
    对于点(x),以任意顺序遍历其子树,然后对于子树中的点(u),检查桶内与(u)路径合法的最大(dep)的点(v),那么贡献就为(dep_u+dep_v-2dep_{lca})
    然后考虑静态链分治。
    静态链分治是解决只有对子树的询问且没有修改的问题的算法。
    我们先轻重链剖分。
    第一步,递归计算所有轻儿子,并且将轻儿子子树内的贡献加到当前节点,计算完之后清空影响。
    第二步,递归计算所有重儿子,并且将重儿子子树内的贡献加到当前节点,计算完之后不清空影响。
    第三步,遍历其所有轻儿子的子树,根据重儿子的影响来计算跨越重儿子与轻儿子的贡献。
    记得计算的同时要更新影响。
    同时为了能在不递归的情况下遍历轻儿子的子树,我们需要记一个欧拉序。
    对于某些问题比如路径问题而言,我们也需要注意一下路径一段在当前点的贡献。
    再以这题为例讲一下具体做法。
    第一步,递归计算所有轻儿子中的路径,当前节点的答案对各个轻儿子的答案取max,计算完之后清空桶。
    第二步,递归计算所有重儿子中的路径,当前节点的答案对各个轻儿子的答案取max,计算完之后不清空桶。
    第三步,根据重儿子的桶计算路径一端在当前点另一端在重儿子子树中的答案。
    第四步,遍历其所有轻儿子子树中的点,根据重桶计算路径一端在当前点另一端在轻儿子子树和路径两端都在轻儿子子树的答案。

    #include<bits/stdc++.h>
    #define pb push_back
    using namespace std;
    namespace IO
    {
        char ibuf[(1<<21)+1],obuf[(1<<21)+1],st[15],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21);
        char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
        void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
        void Put(char x){*oS++=x;if(oS==oT)Flush();}
        char fetch(){char c=Get();while(!islower(c))c=Get();return c;}
        int read(){int x=0;char ch=Get();while(ch>57||ch<48)ch=Get();while(ch>=48&&ch<=57)x=x*10+(ch^48),ch=Get();return x;}
        void write(int x){int top=0;if(!x)Put('0');while(x)st[++top]=(x%10)+48,x/=10;while(top)Put(st[top--]);Put(' ');}
    }
    using namespace IO;
    void max(int &a,int b){a=a>b? a:b;}
    const int N=500007;
    vector<int>G[N],W[N];
    int L[N],R[N],dep[N],size[N],son[N],dis[N],id[N],vis[N],ans[N],t[5000000],T,n;
    void dfs(int u)
    {
        size[u]=1,L[u]=++T,id[T]=u;
        for(int i=0,v;i<G[u].size();++i) dis[v=G[u][i]]=dis[u]^W[u][i],dep[v]=dep[u]+1,dfs(v),size[u]+=size[v],son[u]=size[v]>size[son[u]]? v:son[u];
        R[u]=T;
    }
    void dfs2(int u,int f)
    {
        int i,j,k,v,x,y;
        for(i=0;i<G[u].size();++i) if((v=G[u][i])^son[u]) dfs2(v,0),max(ans[u],ans[v]);
        if(son[u]) dfs2(son[u],1),max(ans[u],ans[son[u]]); 
        if(t[dis[u]]) max(ans[u],t[dis[u]]-dep[u]);
        for(i=0;i<22;++i) if(t[x=(dis[u]^1<<i)]) max(ans[u],t[x]-dep[u]);
        max(t[dis[u]],dep[u]);
        for(i=0;i<G[u].size();++i)
        {
    	if((v=G[u][i])==son[u]) continue;
    	for(j=L[v];j<=R[v];++j)
    	{
    	    if(t[dis[x=id[j]]]) max(ans[u],t[dis[x]]+dep[x]-(dep[u]<<1));
    	    for(k=0;k<22;++k) if(t[y=(dis[x]^1<<k)]) max(ans[u],t[y]+dep[x]-(dep[u]<<1));
    	}
    	for(j=L[v];j<=R[v];++j) max(t[dis[id[j]]],dep[id[j]]); 
        }
        if(!f) for(i=L[u];i<=R[u];++i) t[dis[id[i]]]=0; 
    }
    int main()
    {
        int i,x;char c; n=read();
        for(i=2;i<=n;++i) x=read(),c=fetch(),G[x].pb(i),W[x].pb(1<<c-97);
        dfs(dep[1]=1),dfs2(1,1);
        for(i=1;i<=n;++i) write(ans[i]);
        return Flush(),0;
    }
    
  • 相关阅读:
    各IDE快捷键
    java的GUI之SWT框架 JavaFX框架 配置开发环境(包含但不限于WindowBuilder完整教程,解决Unknown GUI toolkit报错,解决导入SWT包错误)
    20180314 一个浮点数问题
    20180309 算最近新的感悟吧
    20171228 C#值类型和引用类型
    20171129 ASP.NET中使用Skin文件
    20171123初学demo爬去网页资料
    20171018 在小程序页面去获取用户的OpenID
    20171018 微信小程序客户端数据和服务器交互
    20171012 动态爬虫爬取预约挂号有号信息
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/11542830.html
Copyright © 2011-2022 走看看