题目链接

\(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 思路)的更多相关文章

  1. 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 题意 给出一棵树,每条边上有一个字符,字符集大小只 ...

  2. 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 ...

  3. Codeforces 741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(dsu on tree)

    感觉dsu on tree一定程度上还是与点分类似的.考虑求出跨过每个点的最长满足要求的路径,再对子树内取max即可. 重排后可以变成回文串相当于出现奇数次的字母不超过1个.考虑dsu on tree ...

  4. 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,求每个子树中最长的边,满 ...

  5. [Codeforces741D]Arpa's letter-marked tree and Mehrdad's Dokhtar-kosh paths——dsu on tree

    题目链接: Codeforces741D 题目大意:给出一棵树,根为$1$,每条边有一个$a-v$的小写字母,求每个点子树中的一条最长的简单路径使得这条路径上的边上的字母重排后是一个回文串. 显然如果 ...

  6. CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths——dsu on tree

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

  7. CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths (dsu on tree) 题解

    先说一下dsu算法. 例题:子树众数问题. 给出一棵树,每个点有点权,求每个子树中出现次数最多的数的出现次数. 树的节点数为n,\(n \leq 500000\) 这个数据范围,\(O(n \sqrt ...

  8. dsu on tree (树上启发式合并) 详解

    一直都没出过算法详解,昨天心血来潮想写一篇,于是 dsu on tree 它来了 1.前置技能 1.链式前向星(vector 建图) 2.dfs 建树 3.剖分轻重链,轻重儿子 重儿子 一个结点的所有 ...

  9. [探究] dsu on tree,一类树上离线问题的做法

    dsu on tree. \(\rm 0x01\) 前言\(\&\)技术分析 \(\bold{dsu~on~tree}\),中文别称"树上启发式合并"(虽然我并不承认这种称 ...

随机推荐

  1. TrimLeft TrimRight

    strming.TrimLeft();  //将字符串最前面的空格修整掉.当在没有参数的情况下调用时,TrimLeft删除换行符,空格和tab字符. strming.TrimRight()://消除从 ...

  2. 【vim】删除标记内部的文字 di[标记]

    当我开始使用 Vim 时,一件我总是想很方便做的事情是如何轻松的删除方括号或圆括号里的内容.转到开始的标记,然后使用下面的语法: di[标记] 比如,把光标放在开始的圆括号上,使用下面的命令来删除圆括 ...

  3. Linux的capability深入分析(1)【转】

    转自:https://blog.csdn.net/wangpengqi/article/details/9821227 一)概述: )从2.1版开始,Linux内核有了能力(capability)的概 ...

  4. memcmp与strncmp函数【转】

    c中strncmp与memcmp的区别 函数:int memcmp (const void *a1, const void *a2, size_t size)        函数memcmp用于比较字 ...

  5. jdk8系列一、jdk8 Lamda表达式语法、接口的默认方法和静态方法、supplier用法

    一.简介 毫无疑问,Java 8是Java自Java 5(发布于2004年)之后的最重要的版本.这个版本包含语言.编译器.库.工具和JVM等方面的十多个新特性. 在本文中我们将学习这些新特性,并用实际 ...

  6. win10 安装硕正

    提示权限不够,解决方法:根据提示路径手动在路径下建立文件夹

  7. git命令行提交并且同步到远程代码库

    远程代码库以github为例 1.打开 git bash 2.进入项目目录 cd /e/myGitProjects/test 3.提交到本地git仓库 git add -Agit commit -m ...

  8. CGAffineTransform 缩放 / 旋转 / 平移

    CGAffineTransform此类是一个3*3矩阵的变换. - (void)transformImageView { CGAffineTransform t = CGAffineTransform ...

  9. JFreeChart入门

    JFreeChart主要用来各种各样的图表,这些图表包括:饼图.柱状图(普通柱状图以及堆栈柱状图).线图.区域图.分布图.混合图.甘特图以及一些仪表盘等等 (源代码下载) 示例程序运用的jar包: j ...

  10. python+selenium+unittest 实现自动化测试

    示例代码: baidu.py import csv #导入csv模块 from itertools import islice #从itertools导入islice,后边让其默认跳过第一行使用 fr ...