Codeforces.741D.Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(dsu on tree 思路)
\(Description\)
给定一棵树,每条边上有一个字符(a~v)。对每个节点,求它的子树中一条最长的路径,满足 路径上所有边上的字符可以重新排列成一个回文串。输出其最长长度。
\(n\leq 5\times10^5\)。
\(Solution\)
可以构成回文串,即要么所有字符都出现了偶数次,要么有一个出现了奇数次、其余都出现了偶数次。
转化为异或!把每个字符c(0~21)映射到1<<c上去。
令\(s[x]\)表示根节点到\(x\)路径上边权的异或和。那么路径\((u,v)\)满足条件当且仅当\(s[u]\ xor\ s[v]\)等于\(0\)或是某个二次幂。
而路径\((u,v)\)的答案是\(dep[u]+dep[v]-dep[LCA]*2\)。在LCA处计算,这样只需要对每个状态求它最大的\(dep\)。
而且更新时只有23种方式(对于\(s[v]\),可以从\(\max\{dep[s[v]]\}\)和\(\max\{dep[s[v]\
xor\ 2^i]\}\)更新)。
dsu on tree求每个子树的\(\max\{dep[s]\}\)就好了。
复杂度\(O(23n\log n)\)。
//608ms 79100KB
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define gc() getchar()
#define MAXIN 300000
//#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=5e5+5,INF=0x3f3f3f3f;
int Enum,H[N],nxt[N],to[N],ch[N],s[N],f[(1<<22)+2],L[N],R[N],A[N],dep[N],sz[N],son[N],Ans[N];
char IN[MAXIN],*SS=IN,*TT=IN;
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
inline void AE(int u,int v,int c)
{
to[++Enum]=v, nxt[Enum]=H[u], ch[Enum]=c, H[u]=Enum;
}
void DFS1(int x)
{
static int Index=0;
A[L[x]=++Index]=x;
int mx=0; sz[x]=1;
for(int i=H[x],v; i; i=nxt[i])
dep[v=to[i]]=dep[x]+1, s[v]=s[x]^ch[i], DFS1(v), sz[x]+=sz[v], sz[v]>mx&&(mx=sz[v],son[x]=v);
R[x]=Index;
}
inline int Add(int s,int d,int delta)
{
int ans=f[s]+d-delta;
for(int i=0; i<22; ++i) ans=std::max(ans,f[s^(1<<i)]+d-delta);//d[u]+d[v]-d[LCA]*2
return ans;
}
void DFS2(int x,int keep)
{
int ans=0;
for(int i=H[x]; i; i=nxt[i]) if(to[i]!=son[x]) DFS2(to[i],0),ans=std::max(ans,Ans[to[i]]);
if(son[x]) DFS2(son[x],1),ans=std::max(ans,Ans[son[x]]);
ans=std::max(ans,Add(s[x],0,dep[x])), f[s[x]]=std::max(f[s[x]],dep[x]);
for(int i=H[x],v,delta=dep[x]<<1; i; i=nxt[i])
if((v=to[i])!=son[x])
{
for(int j=L[v]; j<=R[v]; ++j) ans=std::max(ans,Add(s[A[j]],dep[A[j]],delta));
for(int j=L[v]; j<=R[v]; ++j) f[s[A[j]]]=std::max(f[s[A[j]]],dep[A[j]]);
}
Ans[x]=ans;
if(!keep) for(int i=L[x]; i<=R[x]; ++i) f[s[A[i]]]=-INF;
}
int main()
{
int n=read();
for(int i=2,x,c; i<=n; ++i)
{
x=read(),c=gc(); while(!isalpha(c)) c=gc();
AE(x,i,1<<c-'a');
}
memset(f,-0x3f,sizeof f);//没有的值不能用0更新
DFS1(1), DFS2(1,1);
for(int i=1; i<=n; ++i) printf("%d ",Ans[i]);
return 0;
}
Codeforces.741D.Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(dsu on tree 思路)的更多相关文章
- 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 题意 给出一棵树,每条边上有一个字符,字符集大小只 ...
- 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(dsu on tree)
感觉dsu on tree一定程度上还是与点分类似的.考虑求出跨过每个点的最长满足要求的路径,再对子树内取max即可. 重排后可以变成回文串相当于出现奇数次的字母不超过1个.考虑dsu on tree ...
- 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,求每个子树中最长的边,满 ...
- [Codeforces741D]Arpa's letter-marked tree and Mehrdad's Dokhtar-kosh paths——dsu on tree
题目链接: Codeforces741D 题目大意:给出一棵树,根为$1$,每条边有一个$a-v$的小写字母,求每个点子树中的一条最长的简单路径使得这条路径上的边上的字母重排后是一个回文串. 显然如果 ...
- CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths——dsu on tree
题目描述 一棵根为1 的树,每条边上有一个字符(a-v共22种). 一条简单路径被称为Dokhtar-kosh当且仅当路径上的字符经过重新排序后可以变成一个回文串. 求每个子树中最长的Dokhtar- ...
- CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths (dsu on tree) 题解
先说一下dsu算法. 例题:子树众数问题. 给出一棵树,每个点有点权,求每个子树中出现次数最多的数的出现次数. 树的节点数为n,\(n \leq 500000\) 这个数据范围,\(O(n \sqrt ...
- dsu on tree (树上启发式合并) 详解
一直都没出过算法详解,昨天心血来潮想写一篇,于是 dsu on tree 它来了 1.前置技能 1.链式前向星(vector 建图) 2.dfs 建树 3.剖分轻重链,轻重儿子 重儿子 一个结点的所有 ...
- [探究] dsu on tree,一类树上离线问题的做法
dsu on tree. \(\rm 0x01\) 前言\(\&\)技术分析 \(\bold{dsu~on~tree}\),中文别称"树上启发式合并"(虽然我并不承认这种称 ...
随机推荐
- nRFgo Studio 和 Nrfjprog 无法找到JLinkARM.dll的解决方法
Segger在第一次安装的时候,会在注册表中添加安装路径的字段,nRF的两个软件就根据这两个注册表字段来寻找JLinkARM.dll.而当你卸载/更新Segger的时候,注册表的相关的字段是不会被修改 ...
- mysql系列九、mysql语句执行过程及运行原理(分组查询和关联查询原理)
一.背景介绍 了解一个sql语句的执行过程,了解一部分都做了什么,更有利于对sql进行优化,因为你知道它的每一个连接.where.分组.子查询是怎么运行的,都干了什么,才会知道怎么写是不合理的. 大致 ...
- Windows10 + Visual Studio 2017 + CMake +OpenCV编译、开发环境配置及测试
由于最近需要使用OpenCV,本人需要在自己的PC上使用OpenCV,因此最近一直在研究如何使用Visual Studio编译OpenCV源代码并搭建开发环境,折腾了很长时间,查阅了很多相关资料,终于 ...
- html5学习第一天
1.语义标签解决方案 <video></video> 属性: controls 显示控制栏 autoplay 自动播放 loop 设置循环播放 多媒体标签在网页中的兼容效果方 ...
- 通达OA批量处理没有结束但前台显示已经结束的流程
问题描述: 通达OA系统出现大量流程没有结束,系统显示结束的问题 通过查询操作系统日志,数据库日志,包括程序日志没有发现异常,通过观察发现大量的流程结束时间都是在2016-02-16 17:32:XX ...
- SIP 认证
理解SIP的认证 1. 认证和加密 认证(Authorization)的作用在于表明自己是谁,即向别人证明自己是谁.而相关的概念是MD5,用于认证安全.注意MD5仅仅是个hash函数而已,并不是 ...
- Android数据存储:File
Android数据存储之File Files:它通过FileInputStream和FileOuputStream对文件进行操作.但是在Android中,文件是一个应用程序私有的,一个应用程序无法读写 ...
- JavaScript 使用 mediaDevices API 选择摄像头
大多数智能手机都有前置和后置摄像头,当你在创建视频应用时你可能想要选择或者切换前置.后置摄像头. 如果你开发的是一款聊天应用,你很可能会想调用前置摄像头,但如果你开发的是一款拍照软件,那么你会更倾向于 ...
- LeetCode(26): 删除排序数组中的重复项
Easy! 题目描述: 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间 ...
- python接口自动化测试二十四:上传多个附件,参数化
# 添加多个附件参数化files = [("1.png", "1.png") ("2.png", "2.png") ]d ...