传送门

题意:

给出一颗以\(1\)为根的有根树,树边带有一个字符(\(a\)~\(v\))的信息。

输出对于每个结点,其子树内最长的简单路径并且满足边上的字符能够组成回文串。

思路:

  • 显然最终的答案分为两部分,子树内部的答案,经过当前根结点的答案。
  • 第一种答案很好处理。类似于点分治,主要处理第二种答案。
  • 树上路径可以考虑找到\(lca\),维护点到根节点的信息。
  • 题目中的回文串可以等价于,出现奇数次的字符不超过\(1\)个。我们将字符状压一下,那么维护点到根的信息就很方便了;同理求出两点间的信息也很方便。
  • 因为要枚举两条链中的结点,我们可以类似于树\(dp\)那样,保留之前的信息,然后枚举这条链更新答案并且更新信息。
  • 这里显然枚举时枚举轻边最优(类似于启发式合并),那么可以采用\(dsu\ on\ tree\),算法会保留重儿子的信息,我们直接暴力轻儿子即可。

根据\(dsu\ on\ tree\)算法的思想,每个结点只会被暴力到\(O(logn)\)次,所以算法的时间复杂度为\(O(nlogn)\)。

感觉挺考察对\(dsu\ on\ tree\)的理解的。。细节见代码吧:

/*
* Author: heyuhhh
* Created Time: 2019/11/15 16:10:20
*/
#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
#define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 5e5 + 5; int n;
char s[N];
vector <int> g[N];
int dis[N], sz[N], bson[N], d[N];
int f[1 << 22];
int ans[N]; void dfs(int u, int fa) {
sz[u] = 1;
int mx = 0;
d[u] = d[fa] + 1;
if(fa) dis[u] = (dis[fa] ^ (1 << (s[u] - 'a')));
for(auto v : g[u]) {
dfs(v, u);
sz[u] += sz[v];
if(sz[v] > mx) {
mx = sz[v]; bson[u] = v;
}
}
} int Max, D; void upd(int u) {
if(f[dis[u]]) Max = max(Max, f[dis[u]] + d[u] - D);
for(int i = 0; i < 22; i++) if(f[dis[u] ^ (1 << i)]) {
Max = max(Max, f[dis[u] ^ (1 << i)] + d[u] - D);
}
} void upd2(int u) {
f[dis[u]] = max(f[dis[u]], d[u]);
} void go(int u) {
upd(u);
for(auto v : g[u]) go(v);
} void go2(int u) {
upd2(u);
for(auto v : g[u]) go2(v);
} void clear(int u) {
f[dis[u]] = 0;
for(auto v : g[u]) clear(v);
} void dfs2(int u, int fa, int op) {
for(auto v : g[u]) if(v != bson[u]) dfs2(v, u, 0);
if(bson[u]) dfs2(bson[u], u, 1);
for(auto v : g[u]) Max = max(Max, ans[v]);
D = 2 * d[u];
for(auto v : g[u]) if(v != bson[u]) {
go(v); go2(v);
}
upd(u); upd2(u);
ans[u] = Max;
if(!op) {
clear(u), Max = 0;
}
} void run(){
for(int i = 2; i <= n; i++) {
int p;
scanf("%d %c", &p, &s[i]);
g[p].push_back(i);
}
dfs(1, 0);
dfs2(1, 0, 1);
for(int i = 1; i <= n; i++) cout << ans[i] << " \n"[i == n];
} int main() {
while(cin >> n) run();
return 0;
}

【cf741】D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(dsu on tree)的更多相关文章

  1. 【CodeForces】741 D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(dsu on tree)

    [题意]给定n个点的树,每条边有一个小写字母a~v,求每棵子树内的最长回文路径,回文路径定义为路径上所有字母存在一种排列为回文串.n<=5*10^5. [算法]dsu on tree [题解]这 ...

  2. 【iOS】7.4 定位服务->2.1.2 定位 - 官方框架CoreLocation: CLLocationManager(位置管理器)

    本文并非最终版本,如果想要关注更新或更正的内容请关注文集,联系方式详见文末,如有疏忽和遗漏,欢迎指正. 本文相关目录: ================== 所属文集:[iOS]07 设备工具 === ...

  3. 【CF741D】Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(dsu on tree)

    题意:我们称一个字符串为周驿东串当且仅当重排它的字符可以组成一个回文串. 给出一个n个点的有根树,根为1,每条边上有一个从a到v的字符,求每个点的子树中所有简单路径可以组成的周驿东串中的最长长度. n ...

  4. 【Telerik】实现列表单元格中添加复选框,进行状态(是、否)判断

    前台界面: 需求:实现对每条细则是否必备进行判断,必备就勾选,否则不勾选. 首先:要保证列表GridView是可编辑的(IsReadOnly=false) 表格代码 其次:单元格的数据绑定要保证是双向 ...

  5. 【K8S】基于Docker+K8S+GitLab/SVN+Jenkins+Harbor搭建持续集成交付环境(环境搭建篇)

    写在前面 最近在 K8S 1.18.2 版本的集群上搭建DevOps环境,期间遇到了各种坑.目前,搭建环境的过程中出现的各种坑均已被填平,特此记录,并分享给大家! 服务器规划 IP 主机名 节点 操作 ...

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

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

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

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

  8. 【翻译】Anatomy of a Program in Memory—剖析内存中的一个程序(进程的虚拟存储器映像布局详解)

    [翻译]Anatomy of a Program in Memory—剖析内存中的一个程序(进程的虚拟存储器映像布局详解) . . .

  9. 【原创】构建高性能ASP.NET站点 第五章—性能调优综述(后篇)

    原文:[原创]构建高性能ASP.NET站点 第五章-性能调优综述(后篇) 构建高性能ASP.NET站点 第五章—性能调优综述(后篇) 前言:本篇主要讲述如何根据一些简单的工具和简单的现象来粗布的定位站 ...

随机推荐

  1. Attaching an entity of type 'xxx' failed because another entity of the same type already has the same primary key value.

    问题的详细描述: Attaching an entity of type 'xxxxx' failed because another entity of the same type already ...

  2. 安装 openmpi 4.0 用于 horovod 编译

    最近编译 horovod框架过程中,需要使用openmpi 4.0但是环境中的openmpi版本比较低,所以在手动安装openmpi4.0 用于编译,下面对过程进行简要记录,进行备忘: curl -O ...

  3. Git操作删除 untracked files

    最近使用git 管理项目的时候,编译过程中出现了很多中间文件,今天发现使用 git clean 命令可以很方便进行清除: # 删除 untracked files git clean -f # 连 u ...

  4. Linux—修改ssh远程登录信息

    修改ssh远程登录端口 1.修改ssh服务的配置文件:/etc/ssh/sshd_config ,将 Port 22 改为 Port 3120 保存退出. [root@localhost ~]# vi ...

  5. android binder 进程间通信机制5-Service注册和代理对象的获取

    ServiceManager,其实也是一个Service,不过它的Server端实现并未使用Binder库的结构实现,而是直接打开binder/dev进行通信的,不具有普遍性. 下面以MediaSer ...

  6. Day6 - Python基础6 模块shelve、xml、re、subprocess、pymysql

    本节目录: 1.shelve模块 2.xml模块 3.re模块 4.subprocess模块 5.logging模块 6.pymysql 1.shelve 模块 shelve模块是一个简单的k,v将内 ...

  7. Global Azure Bootcamp 2019 宁波站活动总结

    4月27日,由微软MVP技术社区发起的Global Azure Bootcamp 2019盛会在全球80多个国家270个城市举办.本次活动由全国众多Azure专家及微软MVP技术社区成员,分别在北京. ...

  8. 百度开源的分布式唯一ID生成器UidGenerator,解决了时钟回拨问题

    UidGenerator是百度开源的Java语言实现,基于Snowflake算法的唯一ID生成器.而且,它非常适合虚拟环境,比如:Docker.另外,它通过消费未来时间克服了雪花算法的并发限制.Uid ...

  9. Java反射简单使用--第一次细致阅读底层代码

    1:所写的东西都经过验证,保证正确,环境jdk8,eclipse2:在例子中,尽量以生产环境中实际代码为例,那种固定值什么的没什么意义 问题: 1:想获取调用方法所需要的参数 2:参数是以json形式 ...

  10. Kubernetes容器集群 - harbor仓库高可用集群部署说明

    之前介绍Harbor私有仓库的安装和使用,这里重点说下Harbor高可用集群方案的部署,目前主要有两种主流的Harbor高可用集群方案:1)双主复制:2)多harbor实例共享后端存储. 一.Harb ...