CF741 D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths
题目意思很清楚了吧,那么我们从重排回文串的性质入手。
很容易得出,只要所有字符出现的次数都为偶数,或者有且只有一个字符出现为奇数就满足要求了。
然后想到什么,Hash?大可不必,可以发现字符\(\in [a,v]\),一共\(22\)种,那么我们套路的状压一下即可。
题目放在一棵树上,我们不禁联想树上常用的算法——倍增,树剖,树分治,树上莫队,LCT,但是好像都不好做。
注意到这是一个静态子树信息维护,所以我们可以用一个比较冷门的算法Dsu on Tree(中文名叫树上启发式合并)
它的大体思路很简单,就是对暴力DFS的过程做了优化。先类似于轻重剖分那样求出轻重儿子,然后每次先暴力递归轻儿子,算完贡献然后删去。
然后再统计重儿子的贡献,做完不再删去,然后最后回溯的时候把轻儿子的再加回去。
由于每跳一次重儿子,子树规模至少减少一半,所以每一个节点最多向上合并\(\log n\)次,所以总复杂度是\(O(n\log n)\)的。
再来考虑这个问题,由于异或以及深度的可减性所以我们可以开一个数组统计子树内每种状态的最大深度,每次根据这个数组更新信息即可。
不过要注意这样做的答案是强制过当前根节点的,不过由于这是个最值问题,我们可以把子树的信息向上取\(\max\)。
虽然会有一个\(22\)的常数,但是你要坚信CF神机是可以跑过去的。
总复杂度\(O(22n\log n)\),常数很小。
CODE
#include<cstdio>
#include<cctype>
#define RI register int
#define CI const int&
#define Tp template <typename T>
#define add(x,y) e[++cnt]=(edge){y,head[x]},head[x]=cnt
using namespace std;
const int N=500005,R=22,status=(1<<R)-1,INF=1e9;
struct edge
{
int to,nxt;
}e[N]; int fa[N],n,head[N],cnt,dep[N],prefix[N],son[N],ans[N],size[N],bit[R+5],f[(1<<R)+5]; char ch;
class FileInputOutput
{
private:
static const int S=1<<21;
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
#define pc(ch) (Ftop<S?Fout[Ftop++]=ch:(fwrite(Fout,1,S,stdout),Fout[(Ftop=0)++]=ch))
char Fin[S],Fout[S],*A,*B; int Ftop,pt[15];
public:
Tp inline void read(T& x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
}
Tp inline void write(T x)
{
if (!x) return (void)(pc('0'),pc(' ')); RI ptop=0;
while (x) pt[++ptop]=x%10,x/=10; while (ptop) pc(pt[ptop--]+48); pc(' ');
}
inline void get_alpha(char& ch)
{
while (!isalpha(ch=tc()));
}
inline void Fend(void)
{
fwrite(Fout,1,Ftop,stdout);
}
#undef tc
#undef pc
}F;
inline void maxer(int& x,CI y)
{
if (y>x) x=y;
}
#define to e[i].to
inline void DFS1(CI now)
{
size[now]=1; for (RI i=head[now];i;i=e[i].nxt)
{
dep[to]=dep[now]+1; prefix[to]^=prefix[now]; DFS1(to);
size[now]+=size[to]; if (size[to]>size[son[now]]) son[now]=to;
}
}
inline void calc(CI now,CI par)
{
RI i; for (i=0;i<=R;++i) maxer(ans[par],dep[now]+f[prefix[now]^bit[i]]);
for (i=head[now];i;i=e[i].nxt) calc(to,par);
}
inline void Add(CI now)
{
maxer(f[prefix[now]],dep[now]); for (RI i=head[now];i;i=e[i].nxt) Add(to);
}
inline void Del(CI now)
{
f[prefix[now]]=-INF; for (RI i=head[now];i;i=e[i].nxt) Del(to);
}
inline void DFS2(CI now)
{
RI i; for (i=head[now];i;i=e[i].nxt) if (to!=son[now])
DFS2(to),Del(to); if (son[now]) DFS2(son[now]);
maxer(f[prefix[now]],dep[now]); for (i=0;i<=R;++i)
maxer(ans[now],dep[now]+f[prefix[now]^bit[i]]);
for (i=head[now];i;i=e[i].nxt) if (to!=son[now]) calc(to,now),Add(to);
}
#undef to
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
RI i; for (F.read(n),i=2;i<=n;++i) F.read(fa[i]),F.get_alpha(ch),
add(fa[i],i),prefix[i]=1<<ch-'a'; for (i=0;i<=status;++i)
f[i]=-INF; for (i=0;i<R;++i) bit[i]=1<<i;
for (DFS1(1),DFS2(1),i=1;i<=n;++i) ans[i]-=2*dep[i];
for (i=n;i;--i) maxer(ans[fa[i]],ans[i]); for (i=1;i<=n;++i)
F.write(ans[i]); return F.Fend(),0;
}
CF741 D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths的更多相关文章
- CF 741D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths [dsu on tree 类似点分治]
D. Arpa's letter-marked tree and Mehrdad's Dokhtar-kosh paths CF741D 题意: 一棵有根树,边上有字母a~v,求每个子树中最长的边,满 ...
- Codeforces 741 D - Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths
D - Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths 思路: 树上启发式合并 从根节点出发到每个位置的每个字符的奇偶性记为每个位 ...
- CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths
CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths 好像这个题只能Dsu On Tree? 有根树点分治 统计子树过x的 ...
- codeforces 741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths
题目链接:Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths 第一次写\(dsu\ on\ tree\),来记录一下 \(dsu\ o ...
- codeforces 741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(启发式合并)
codeforces 741D Arpa's letter-marked tree and Mehrdad's Dokhtar-kosh paths 题意 给出一棵树,每条边上有一个字符,字符集大小只 ...
- CF 741 D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths
D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths http://codeforces.com/problemset/probl ...
- 【cf741】D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(dsu on tree)
传送门 题意: 给出一颗以\(1\)为根的有根树,树边带有一个字符(\(a\)~\(v\))的信息. 输出对于每个结点,其子树内最长的简单路径并且满足边上的字符能够组成回文串. 思路: 显然最终的答案 ...
- [Codeforces741D]Arpa's letter-marked tree and Mehrdad's Dokhtar-kosh paths——dsu on tree
题目链接: Codeforces741D 题目大意:给出一棵树,根为$1$,每条边有一个$a-v$的小写字母,求每个点子树中的一条最长的简单路径使得这条路径上的边上的字母重排后是一个回文串. 显然如果 ...
- Codeforces 741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(dsu on tree)
感觉dsu on tree一定程度上还是与点分类似的.考虑求出跨过每个点的最长满足要求的路径,再对子树内取max即可. 重排后可以变成回文串相当于出现奇数次的字母不超过1个.考虑dsu on tree ...
随机推荐
- Android项目实战(五十):微信支付 坑总结
大部分APP必备需求,使用总结 Android接入文章在此:官方文档 文档很简单,Android分为四步: 1.后台配置 2.Android 内 注册appId 3.Android 内 调起支付 4. ...
- android常犯错误记录(一)
错误:Error:Error: Found item Attr/border_width more than one time 这个容易,属性相同了,按照提示查询一下找出来删了就行了,注意大小写很容易 ...
- php post接口,注册功能
功能描述:仅输入手机号和密码,实现注册功能.手机号有简单的验证,不可重复输入,否则会报500错误. 在使用 RestClient 进行post测试时,如果你把参数放在 [Headers]区块了,那么, ...
- 品牌电脑硬盘损坏后,使用MediaCreationTool从微软官方下载正版Windows到USB做安装盘
最近我的一台台式机电脑的硬盘损坏了.一开始是速度逐渐变慢,后来慢得难以忍受,有时半天无响应.查看 Windows event ,发现有 id 为 7 的磁盘报错.使用 Windows 8.1 家庭版自 ...
- CentOS基本的命令与快捷建
由于我的计算机在安装linux系统时,计算机出现了问题,并没有安装ubuntu而是安装的centos.虽然两者属于linux的不同版本,但是在具体的操作上大同小异.在学习linux的各种指令和快捷键的 ...
- UnrealEd3视图导航及常用快捷键
本博客使用的版本:2010-08 [更多其他的UE3版本][tps所用版本: 2011-02] [最新的UE3版本 -- 2015-02] [unreal engine wiki 中文w ...
- Spring入门详细教程(四)
前言 本篇紧接着spring入门详细教程(三),建议阅读本篇前,先阅读第一篇,第二篇以及第三篇.链接如下: Spring入门详细教程(一) https://www.cnblogs.com/jichi/ ...
- java 根据实体对象生成 增删改的SQL语句 ModelToSQL
package com.xxx.utils; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import jav ...
- 文件服务器HFS
用途:用于文件共享(类似FTP) 官网:http://www.rejetto.com/hfs/?f=ss 优点:比起apache,它有界面方便查看当前正连接的主机 如果在内网环境下进行文件共享的话,可 ...
- 一、JSP标签介绍,自定义标签
一.JSP标签介绍 1. 标签库有什么作用 自定义标签库是一种优秀的表现层技术,之前介绍的MVC模式,我们使用jsp作为表现层,但是jsp语法嵌套在html页面,美工还是很难直接参与开发,并且jsp脚 ...