感觉dsu on tree一定程度上还是与点分类似的。考虑求出跨过每个点的最长满足要求的路径,再对子树内取max即可。

  重排后可以变成回文串相当于出现奇数次的字母不超过1个。考虑dsu on tree,容易想到遍历时记录每种情况的最大深度,合并时类似点分的逐个计算贡献再合并即可。这里有个问题是得到某子树信息后,对于原来的根来说,这个信息还要再加上一个偏移量,但直接暴力显然复杂度就不对了。实际上维护信息过程中不断传递偏移量即可。

  一开始就发现了这个题只开了256M,于是机智的开了个map,悲惨的T掉了。然而题面里深藏不露的说了一句字母范围在a~v。这啥思博题啊。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 500010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<''||c>'')) c=getchar();return c;}
int gcd(int n,int m){return m==?n:gcd(m,n%m);}
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
int n,a[N],p[N],fa[N],size[N],deep[N],son[N],len[N],ans[N],t,f[<<];
struct data{int to,nxt;
}edge[N];
void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],len[y]=z,p[x]=t;}
void make(int k)
{
size[k]=;
for (int i=p[k];i;i=edge[i].nxt)
{
deep[edge[i].to]=deep[k]+;
make(edge[i].to);
size[k]+=size[edge[i].to];
if (size[edge[i].to]>size[son[k]]) son[k]=edge[i].to;
}
}
inline int rev(int x){return (<<)-^x;}
void update(int k,int x,int op)
{
if (op==) f[k]=max(f[k],x);
else f[k]=;
}
void add(int k,int x,int op)//对子树内统计信息时,偏移量为x
{
update(x,deep[k],op);
for (int i=p[k];i;i=edge[i].nxt)
add(edge[i].to,x^(<<len[edge[i].to]),op);
}
int calc(int k,int x)
{
int ans=f[x]+deep[k];
for (int i=;i<;i++) ans=max(ans,deep[k]+f[x^(<<i)]);
if (ans==deep[k]) ans=-N;
for (int i=p[k];i;i=edge[i].nxt)
ans=max(ans,calc(edge[i].to,x^(<<len[edge[i].to])));
return ans;
}
int dfs(int k)//获得的该子树信息的偏移量
{
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=son[k])
{
int delta=dfs(edge[i].to);
ans[k]=max(ans[k],ans[edge[i].to]);
add(edge[i].to,delta,-);
}
int delta=;
if (son[k])
{
delta=dfs(son[k])^(<<len[son[k]]);ans[k]=max(ans[k],ans[son[k]]);
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=son[k])
{
ans[k]=max(ans[k],calc(edge[i].to,delta^(<<len[edge[i].to]))-(deep[k]<<));
add(edge[i].to,delta^(<<len[edge[i].to]),);
}
}
ans[k]=max(ans[k],f[delta]-deep[k]);
for (int i=;i<;i++) ans[k]=max(ans[k],f[delta^(<<i)]-deep[k]);
update(delta,deep[k],);
return delta;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("741D.in","r",stdin);
freopen("741D.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read();
for (int i=;i<=n;i++)
fa[i]=read(),addedge(fa[i],i,getc()-'a');
deep[]=;make();
dfs();
for (int i=;i<=n;i++) printf("%d ",ans[i]);
return ;
}

最新文章

  1. 头像上传,拖拽,裁切(HTML5)版本
  2. PowerShell脚本:随机密码生成器
  3. perl 递归地遍历目录下的文件
  4. python cmd命令调用
  5. 在 InstantRails 环境下,安装使用 redMine
  6. html中的a标签的target属性的四个值的区别?
  7. 苹果App Store开发者帐户从申请,验证,到发布应用(3)
  8. python之pymysql模块学习(待完善...)
  9. 全新的.NET解释器 - Mono已经到来
  10. Kafka实战分析(一)- 设计、部署规划及其调优
  11. Solr4.7.0连接PostgreSQL
  12. 方位话机X2主、备用服务器问题
  13. 20165231 预备作业二:学习基础和C语言基础调查
  14. 第21章 RTX 低功耗之睡眠模式
  15. 常用数据库2 mysql
  16. Eclipse解决运行、启动缓慢问题思路
  17. 团队冲刺--Seven
  18. linux用户管理中两个重要的“父子”配置文件
  19. u-boot中添加自定义命令
  20. jfinal控制器添加多个拦截器

热门文章

  1. C++ 文件和流
  2. C# Hashtable vs Dictionary 学习笔记
  3. 讲一下Asp.net core MVC2.1 里面的 ApiControllerAttribute (转载)
  4. npm install报错 npm ERR! enoent ENOENT: no such file or directory
  5. Opencv 2.4.10 +VS2010 项目配置
  6. 【UFUN开发板评测】小巧而不失精致,简单而不失内涵——uFun开发板开箱爆照
  7. TomCat 再次发布我的程序
  8. Redis常用操作-------List(列表)
  9. [BUAA软工]第二次博客作业---结对编程
  10. 自己搭建的一个react脚手架