zoukankan      html  css  js  c++  java
  • CodeForces 741D....path【树上启发式合并】

    传送门

    题意

    一棵根为1的树,每条边上有一个字符(a-v共22种)。 一条简单路径被称为Dokhtar-kosh当且仅当路径上的字符经过重新排序后可以变成一个回文串。 求每个子树中最长的Dokhtar-kosh路径的长度。

    题解

    既然要重新排列,那么这个路径的条件就是:

    • 简单路径
    • 路径中 22 种字母最多只能由一种字母数量为奇数。
      如果我一直从某点到根节点的字母的情况,那么对于另一个点,如果在所有字母中奇偶性与之相同或者只有1种奇偶性不同,那么这两个点之间的简单路径就是Dokhtar-kosh。
      然后这样的统计可以使用树上启发式合并,方法和什么点分治差不多。

    代码

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <queue>
    #define xx first
    #define yy second
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> PII;
    const int inf=0x3f3f3f3f;
    const LL INF=0x3f3f3f3f3f3f3f3f;
    const int N=5e5+10;
    const int M=1e6+10;
    int n,sta[N],dep[N],siz[N],son[N];
    int ans[N],maxlen[1<<22],rt,node[N],cnt;
    vector<PII> g[N];
    
    void predfs(int u,int fa,int state){
    	siz[u]=1;sta[u]=state;dep[u]=dep[fa]+1;
    	for(PII e:g[u]){
    		int v=e.xx,c=e.yy;
    		if(v==fa) continue;
    		predfs(v,u,state^(1<<c));
    		siz[u]+=siz[v];
    		if(siz[v]>siz[son[u]]) son[u]=v;
    	}
    }
    
    void getnode(int u,int fa){
    	node[++cnt]=u;
    	for(PII e:g[u]) if(e.xx!=fa) getnode(e.xx,u);
    }
    
    void clear(int u,int fa){
    	maxlen[sta[u]]=-inf;
    	for(PII e:g[u]) if(e.xx!=fa) clear(e.xx,u);
    }
    
    void calc(int u){
    	ans[rt]=max(ans[rt],maxlen[sta[u]]+dep[u]-2*dep[rt]);
    	for(int i=0;i<22;i++)
    		ans[rt]=max(ans[rt],maxlen[sta[u]^(1<<i)]+dep[u]-2*dep[rt]);
    }
    
    void dfs(int u,int fa,bool keep){
    	for(PII e:g[u]){
    		if(e.xx==fa||e.xx==son[u]) continue;
    		dfs(e.xx,u,false);
    	}
    	if(son[u]) dfs(son[u],u,true);
    	rt=u;
    	calc(u);
    	maxlen[sta[u]]=max(maxlen[sta[u]],dep[u]);
    	for(PII e:g[u]){
    		if(e.xx==fa||e.xx==son[u]) continue;
    		cnt=0;
    		getnode(e.xx,u);
    		for(int i=1;i<=cnt;i++) calc(node[i]);
    		for(int i=1;i<=cnt;i++) maxlen[sta[node[i]]]=max(maxlen[sta[node[i]]],dep[node[i]]);
    	}
    	for(PII e:g[u]) if(e.xx!=fa) ans[u]=max(ans[u],ans[e.xx]);
    	if(!keep) clear(u,fa);
    }
    
    int main(){
    	memset(maxlen,0xc0,sizeof(maxlen));
    	scanf("%d",&n);
    	for(int v=2,u;v<=n;v++){
    		char s[10];
    		scanf("%d%s",&u,s);
    		g[u].push_back({v,s[0]-'a'});
    		g[v].push_back({u,s[0]-'a'});
    	}
    	predfs(1,0,0);
    	dfs(1,0,true);
    	for(int i=1;i<=n;i++) printf("%d ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    mysql定时器,定时查询数据库,把查询结果插入到一张表中 阿星小栈
    如何写mysql的定时任务 阿星小栈
    利用mysql游标循环结果集 阿星小栈
    页面可见生Page Visibility
    css之z-index
    css之页面三列布局之左右两边宽度固定,中间自适应
    css之页面两列布局
    jquery源码学习之extend
    jquery源码学习之queue方法
    HTTP状态码详解
  • 原文地址:https://www.cnblogs.com/BakaCirno/p/12606917.html
Copyright © 2011-2022 走看看