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 ...
随机推荐
- Okhttp3请求网络开启Gzip压缩
前沿 首先OkHttp3是支持Gzip解压缩的,不过我们要明白,它是支持我们在发起请求的时候自动加入header,Accept-Encoding: gzip,而我们的服务器返回的时候header中有C ...
- sql 语句-初级进阶(一)
以下所有的sql语句是根据个人资料进行操作,为方便大家操作联系,附上链接:: 链接:https://pan.baidu.com/s/14LmWyhJPQRzpjURQBKM4mA 提取码:wu1q ...
- Java中数组、List、Set互相转换
数组转List String[] staffs = new String[]{"Tom", "Bob", "Jane"}; List sta ...
- c/c++ lambda 表达式 介绍
lambda 表达式 介绍 问题:假设有个需求是,在vector<string>找出所有长度大于等于4的元素.标准库find_if函数的第三参数是函数指针,但是这个函数指针指向的函数只能接 ...
- IPerf——网络测试工具介绍与源码解析(5)
本篇随笔讲述一下TCP协议下,双向测试模式和交易测试模式下客户端和服务端执行的情况: 双向测试模式: 官方文档的解释 Run Iperf in dual testing mode. This will ...
- xp,windows7,windows8,windows10那个系统好用些
Windows XP:这曾经是微软史上最好的.最受欢迎.最受好评的可以说空前绝后的系统,虽然,XP系统对电脑配置的要求很低,基本现在所有的电脑都支持安装该系统,可它太老旧了,到2014年4-5月份微软 ...
- python发展史
一:Python介绍 python的创始人为吉多·范罗苏姆(Guido van Rossum)(龟叔).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹 打发时间,决心开发一个新的脚本解释程序, ...
- PHP实现类似题库抽题效果
PHP实现类似题库抽题效果 大家好,我顾某人又回来了,最近学了一点PHP,然后就想写个简单小例子试试,于是就写了一个类似于从题库抽题的东西,大概就是先输入需要抽题的数量,然后从数据库中随机抽取题目. ...
- Servlet(四):转发与重定向、路径问题
在上次的小案例中用到了转发的技术,今天来仔细聊聊转发和重定向的问题,以及一些小知识的汇总. 一.转发 1.转发的概念 转发主要是将浏览器的请求交给另外一个servlet或jsp来处理,借助reques ...
- MySQL 数据库初识
一.数据库概述 (详情参考:https://www.cnblogs.com/clschao/articles/9907529.html) 1.概念:存储数据,共享数据 数据库,简而言之可视为电子化的文 ...