题目链接

题目

题目描述

芭芭拉这次来到了一棵字母树,这同样是一棵无根树,每个节点上面有一个小写字母。

芭芭拉想知道,自己从x冲刺到y,从x走到y收集所有字母,选择其中一部分字母组成一个回文串,这个回文串的最大长度是多少?

同样的,芭芭拉冲刺的时候是不能掉头的。

一共有q次询问。每次的询问是独立的(即本次收集字母不影响之后的询问,每次询问时字母都是未被收集状态)。

输入描述

第一行有一个正整数 $ n\ $ 。

接下来的 $ n-1\ $ 行,每行输入两个正整数 $ x\ $ 和 $ y\ $ ,代表 $ x\ $ 和 $ y\ $ 之间有一条无向边相连。

接下来一行有一个长度为 $ n\ $ 的字符串,字符串仅由小写字母构成。第 $ i\ $ 个字符表示节点 $ i\ $ 上的字母。

接下来一行是一个正整数 $ q\ $ ,代表询问次数。

接下来的 $ q\ $ 行,每行两个正整数 $ x\ $ 和 $ y\ $ 。

(保证输入一定是一棵树)

$(1≤n,q≤100000,1≤x,y≤n) \ $

输出描述

对应每次询问,输出一个正整数,代表回文串的最大长度。

示例1

输入

5
1 2
1 3
2 4
2 5
abcba
3
4 5
1 2
3 3

输出

3
1
1

说明

这棵树的构造如下:

对于第一个询问,芭芭拉冲刺的路径是4-2-5,收集的字母有两个b一个a,可以构建的最长回文串是"bab",长度为3。

对于第二个询问,芭芭拉冲刺的路径是1-2,收集的字母有一个b一个a,可以构建的最长回文串是"a"(也可以是"b"),长度为1。

对于第三个询问,芭芭拉起点和终点都是3,所以站在原地不动,收集的字母有只有一个c,可以构建的最长回文串是"c",长度为1。

题解

知识点:树链剖分,枚举,前缀和。

考虑用树剖,然后用前缀和维护一条树链的各个字母的数量。

每次询问时,求出路径字母数量和后,构造最长的回文串即可:偶数字母直接加,奇数字母只能完整加一次,剩下的只能减 \(1\) 。

时间复杂度 \(O(n + q\log n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long; struct HLD {
vector<int> siz, dep, fat, son, top, dfn, L, R; HLD() {}
HLD(int rt, const vector<vector<int>> &g) { init(rt, g); } void init(int rt, const vector<vector<int>> &g) {
assert(g.size() >= 2);
int n = g.size() - 1;
siz.assign(n + 1, 0);
dep.assign(n + 1, 0);
fat.assign(n + 1, 0);
son.assign(n + 1, 0);
top.assign(n + 1, 0);
dfn.assign(n + 1, 0);
L.assign(n + 1, 0);
R.assign(n + 1, 0); function<void(int, int)> dfsA = [&](int u, int fa) {
siz[u] = 1;
dep[u] = dep[fa] + 1;
fat[u] = fa;
for (auto v : g[u]) {
if (v == fa) continue;
dfsA(v, u);
siz[u] += siz[v];
if (siz[v] > siz[son[u]]) son[u] = v;
}
};
dfsA(rt, 0); int dfncnt = 0;
function<void(int, int)> dfsB = [&](int u, int tp) {
top[u] = tp;
dfn[++dfncnt] = u;
L[u] = dfncnt;
if (son[u]) dfsB(son[u], tp);
for (auto v : g[u]) {
if (v == fat[u] || v == son[u]) continue;
dfsB(v, v);
}
R[u] = dfncnt;
};
dfsB(rt, rt);
}
}; const int N = 100007;
vector<int> g[N];
HLD hld;
int sum[N][26]; int path_query(int u, int v) {
auto &top = hld.top;
auto &dep = hld.dep;
auto &fat = hld.fat;
auto &L = hld.L;
int cnt[26] = { 0 };
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
for (int i = 0;i < 26;i++) cnt[i] += sum[L[u]][i] - sum[L[top[u]] - 1][i];
u = fat[top[u]];
}
if (dep[u] > dep[v]) swap(u, v);
for (int i = 0;i < 26;i++) cnt[i] += sum[L[v]][i] - sum[L[u] - 1][i]; int ans = 0;
bool odd = 0;
for (int i = 0;i < 26;i++) {
ans += cnt[i] - ((cnt[i] & 1) && odd);
odd |= cnt[i] & 1;
}
return ans;
} int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n;
cin >> n;
for (int i = 1;i <= n - 1;i++) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
hld.init(1, vector<vector<int>>(g, g + n + 1)); for (int i = 1;i <= n;i++) {
char ch;
cin >> ch;
sum[hld.L[i]][ch - 'a']++;
}
for (int i = 1;i <= n;i++)
for (int j = 0;j < 26;j++)
sum[i][j] += sum[i - 1][j]; int q;
cin >> q;
while (q--) {
int u, v;
cin >> u >> v;
cout << path_query(u, v) << '\n';
}
return 0;
}

NC213912 芭芭拉冲鸭~(续)的更多相关文章

  1. .Net Core MVC 网站开发(Ninesky) 2.3、项目架构调整(续)-使用配置文件动态注入

    上次实现了依赖注入,但是web项目必须要引用业务逻辑层和数据存储层的实现,项目解耦并不完全:另一方面,要同时注入业务逻辑层和数据访问层,注入的服务直接写在Startup中显得非常臃肿.理想的方式是,w ...

  2. [.NET] C# 知识回顾 - 委托 delegate (续)

    C# 知识回顾 - 委托 delegate (续) [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6046171.html 序 上篇<C# 知识回 ...

  3. iOS 开发者账号到期续费流程

    1.登录developer.apple.com,查看到期时间 2.到期提醒通知,点击Renew Membership续费(一般提前一个月提醒续费) 3.个人开发者账号续费需要支付 688人民币/年(9 ...

  4. 微信公众号开发系列教程一(调试环境部署续:vs远程调试)

    http://www.cnblogs.com/zskbll/p/4080328.html 目录 C#微信公众号开发系列教程一(调试环境部署) C#微信公众号开发系列教程一(调试环境部署续:vs远程调试 ...

  5. CI-持续集成(1)-软件工业“流水线”概述

    CI-持续集成(1)-软件工业“流水线”概述 1   概述 持续集成(Continuous integration)是一种软件开发实践,即团队开发成员经常集成它们的工作,通过每个成员每天至少集成一次, ...

  6. 分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility (续3篇-导出时动态生成多Sheet EXCEL)

    ExcelUtility 类库经过我(梦在旅途)近期不断的优化与新增功能,现已基本趋向稳定,功能上也基本可以满足绝大部份的EXCEL导出需求,该类库已在我们公司大型ERP系统全面使用,效果不错,今天应 ...

  7. [译]Godot系列教程三 - 场景实例化(续)

    场景实例化(续) 要点 场景实例化带来很多便利的用法,总体来说有: 将场景细分,更便于管理 相对于某些引擎中的Prefab组件更灵活,并且在许多方面更强大 是一种设计更复杂的游戏流程甚至UI的方式 这 ...

  8. 【小白的CFD之旅】13 敲门实例【续3】

    接上文[小白的CFD之旅]12 敲门实例[续2] 4 Results4.1 计算监测图形4.2 Graphics4.2.1 壁面温度分布4.2.2 创建截面4.2.3 显示截面物理量4.2.4 Pat ...

  9. 【小白的CFD之旅】12 敲门实例【续2】

    接上文[小白的CFD之旅]敲门实例[续] 主要内容 3 Solution3.1 Solution Methods3.2 Solution Controls3.3 Monitors3.4 Report ...

  10. jquery实现简单瀑布流布局(续):图片懒加载

    # jquery实现简单瀑布流布局(续):图片懒加载 这篇文章是jquery实现简单瀑布流布局思想的小小扩展.代码基于前作的代码继续完善. 图片懒加载就是符合某些条件时才触发图片的加载.最常见的具体表 ...

随机推荐

  1. python · ssh · SQL | python 连接远程 SQL 数据库

    python 连接本地 SQL 的 教程存档. 如果要连接远程的 SQL 数据库,需要先开一个 ssh 连接,在 ssh 连接里写 pymysql 的 connect 代码. 代码如下: ''' pi ...

  2. Redis 主从复制架构配置及原理

    本文为博主原创,未经允许不得转载: 目录: 1. Redis 主从复制架构搭建 2. Redis 主从架构原理 3. Redis 断点续传 4. Jedis 连接 redis 主从架构一般配置一主多从 ...

  3. centos 安装python3导致yum报错

    centos yum报错 File "/usr/bin/yum", line 30 except KeyboardInterrupt, e: 报错: 报错一: File " ...

  4. 远程连接-ssh

  5. 百度网盘(百度云)SVIP超级会员共享账号每日更新(2024.01.08)

    一.百度网盘SVIP超级会员共享账号 可能很多人不懂这个共享账号是什么意思,小编在这里给大家做一下解答. 我们多知道百度网盘很大的用处就是类似U盘,不同的人把文件上传到百度网盘,别人可以直接下载,避免 ...

  6. [转帖]实战演练 | Navicat 数据生成功能

    https://zhuanlan.zhihu.com/p/631823381 数据生成的目的是依据某个数据模型,从原始数据通过计算得到目标系统所需要的符合该模型的数据.数据生成与数据模型是分不开的,数 ...

  7. [转帖]linux中Shell日期转为时间戳的方法

    http://www.nndssk.com/xtwt/169617hFPRvq.html shell中获取时间戳的方式为:date -d "$currentTime" +%s $ ...

  8. [转帖]【JVM】JVM概述

    1.JVM定义 JVM 是Java Virtual Machine(JVM )的缩写,Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令进行执行,这样实现了Java"一次编译, ...

  9. FS OFS RS ORS

  10. pytest.ini配置文件

    pytest.ini文件是pytest框架独有的配置文件,主要作用就是在运行pytest.main时可指定运行顺序,也 就相当于在Terminal输入pytest+参数+路径效果一致,下面介绍几种简单 ...