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

    题目传送门

    分析:
    一个路径的字符串能够重排序构成回文串当且仅当其中最多有一种字符数量为奇数
    22种字符,按该种字符个数是否为奇数构成长度为22的二进制数
    其中就只有23种情况符合要求
    两条路径合并只需要按位异或了

    对于每个点(x),建立一个以从它开始向下延伸的路径的值作为下标的桶,
    一个一个儿子地做,每次加入一个儿子的子树时,先遍历这个子树的点(u),在前面儿子的子树构成的桶里面查询合法的下标中的值
    不难发现桶中代表节点(v)(u)(LCA)就是(x)
    这个桶存的值是目前最深的路径,当(u,x)确定时,我们当然是要贪心地选最深的点
    儿子的信息要往上合并

    其实可以考虑线段树合并,但是空间复杂度(O(nlogn))难以接受
    于是使用优雅的暴力:Dsu On Tree

    当我们需要对于每一个子树都进行遍历,并且信息可以用桶等方式进行(O(1))修改和查询时
    所有点共用一个桶,每棵子树暴力遍历修改,暴力查询,暴力清零
    显然复杂度为(O(sum_{i=1}^{n}sz[i])),其中(sz)为子树大小,这是(O(n^2))级别的,会超时
    儿子遍历完,开始遍历父亲时,我们可以选择最后一个儿子不清空,直接归并到父亲,父亲在遍历时就不遍历这个儿子的子树
    贪心地想,肯定是选重儿子不清空而归并
    这下子复杂度变成(O(sum_{i=1}^{n}sz[i]-sz[son[i]])),其中(son)表示重儿子
    这个复杂度不太好算,我们换个角度考虑
    对于每个点,如果暴力做上面的过程,那么他会被访问(dep)次,总复杂度为(O(n^2))
    如果使用dsu on tree,每个点到根的路径上,只有重链底端的点会访问它,也就是轻边的父节点
    又发现路径上的轻边是(O(logn))级别的,最终复杂度就变成了(O(nlogn))

    最终,dsu on tree的时间复杂度为(O(nlogn)),空间复杂度为(O(n))
    可以说是非常优雅的暴力

    本题查询复杂度为(O(23))总复杂度为(O(23nlogn))
    CF神仙机子肯定能跑(大嘘

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<map>
    #include<queue>
    #include<vector>
    
    #define maxn 2000005
    #define MOD 1000000007
    #define INF 0x3f3f3f3f
    
    using namespace std;
    
    inline long long getint()
    {
        long long num=0,flag=1;char c;
        while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
        while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
        return num*flag;
    }
    
    int n,q;
    int fir[maxn],nxt[maxn],to[maxn],len[maxn],cnt;
    int sz[maxn],dpt[maxn],son[maxn],pos[maxn],id[maxn],dis[maxn],cur;
    int b[1<<23],ans[maxn];
    
    inline void newnode(int u,int v,int w)
    {to[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt,len[cnt]=w;}
    inline void dfs1(int u)
    {
    	sz[u]=1,pos[u]=++cur,id[cur]=u;
    	for(int i=fir[u];i;i=nxt[i])
    	{
    		dpt[to[i]]=dpt[u]+1,dis[to[i]]=dis[u]^len[i];
    		dfs1(to[i]),sz[u]+=sz[to[i]];
    		if(sz[son[u]]<sz[to[i]])son[u]=to[i];
    	}
    }
    
    inline void check(int u,int lca)
    {
    	if(b[dis[u]])ans[lca]=max(ans[lca],b[dis[u]]+dpt[u]-2*dpt[lca]);
    	for(int i=0;i<22;i++)if(b[dis[u]^(1<<i)])ans[lca]=max(ans[lca],b[dis[u]^(1<<i)]+dpt[u]-2*dpt[lca]);
    }
    
    inline void dfs2(int u,int kp)
    {
    	for(int i=fir[u];i;i=nxt[i])if(to[i]!=son[u])dfs2(to[i],0),ans[u]=max(ans[u],ans[to[i]]);
    	if(son[u])dfs2(son[u],1),ans[u]=max(ans[u],ans[son[u]]);
    	check(u,u);b[dis[u]]=max(b[dis[u]],dpt[u]);
    	for(int i=fir[u];i;i=nxt[i])if(to[i]!=son[u])
    	{
    		for(int j=pos[to[i]];j<pos[to[i]]+sz[to[i]];j++)check(id[j],u);
    		for(int j=pos[to[i]];j<pos[to[i]]+sz[to[i]];j++)b[dis[id[j]]]=max(b[dis[id[j]]],dpt[id[j]]);
    	}
    	if(!kp)for(int i=pos[u];i<pos[u]+sz[u];i++)b[dis[id[i]]]=0;
    }
    
    int main()
    {
    	n=getint();
    	for(int i=2;i<=n;i++)
    	{
    		int u=getint();
    		newnode(u,i,1<<(getchar()-97));
    	}
    	dfs1(1),dfs2(1,1);
    	for(int i=1;i<=n;i++)printf("%d%c",ans[i],i==n?'
    ':' ');
    }
    

  • 相关阅读:
    Apache Flink教程
    开发EasyRTSPServer组件时如何使用ffserver搭建一套RTSP流媒体服务器并分发RTSP视频流?
    【解决方案】用科技的力量构筑“食品安全”防火墙,明厨亮灶保护“舌尖上的安全”
    RTSP/GB28181视频智能分析人脸识别系统EasyCVR除人脸门禁外还可以运用到哪些方向?
    GB28181/RTSP/SDK/Ehome协议安防视频融合平台EasyCVR新增分组管理功能操作介绍
    【解决方案】RTSP/GB28181协议视频平台EasyCVR在烟草行业是如何搭建一套网络视频监控系统的?
    【解决方案】RTSP/GB28181协议视频融合监控平台EasyCVR在三维可视化系统中的应用
    linux 学习随记---设置日志时间戳
    服务器端口总结
    (转载)PowerShell因为在此系统中禁止执行脚本解决方法
  • 原文地址:https://www.cnblogs.com/Darknesses/p/13054872.html
Copyright © 2011-2022 走看看