题目链接

题目

题目描述

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

芭芭拉想知道,自己从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. hello world 的并发实现

    本篇文章将介绍 hello world 的并发实现,其中涉及到的知识有: 并发与并行 GPM 调度系统 并发与并行 并发不是并行.并发是同时管理很多事情,这些事情可能只做了一半就被暂停做别的事情了.而 ...

  2. VUEX 使用学习六 : modules

    转载请注明出处: 当Store中存放了非常多非常大的共享数据对象时,应用会变的非常的复杂,Store对象也会非常臃肿,所以Vuex提供了一个Module模块来分隔Store.通过对Vuex中的Stor ...

  3. 01-Shell脚本入门

    1.Shell介绍 1.1 疑问 linux系统是如何操作计算机硬件CPU,内存,磁盘,显示器等? 答: 使用linux的内核操作计算机的硬件 1.2 Shell介绍 通过编写Shell命令发送给li ...

  4. LaTeX 公式识别问题

    问题 想要方便的图片公式识别工具来写Latex(论文)/markdown(笔记)文件 工具推荐 1.mathpix 识别成功率最高(无论是多行,表格表现都非常良好),最好用的工具,但是收费高且付费麻烦 ...

  5. [转帖]【终端使用】"usermod"命令 和 组(包括:主组、附加组)

      "usermod"命令,可以用来设置用户账户的 主组.附加组.登录使用的Shell. 命令 作用 usermod -g 组名 用户名 修改用户的主组(gid) usermod ...

  6. [转帖]数据库篇-MySql架构介绍

    https://zhuanlan.zhihu.com/p/147161770 公众号-坚持原创,码字不易.加微信 : touzinv 关注分享,手有余香~ 本篇咱们也来聊聊mysql物理和逻辑架构,还 ...

  7. [转帖]Debian9换源(阿里源)(Linux子系统)

    http://www.taodudu.cc/news/show-5410026.html?action=onClick 默认你已经装好Linux子系统. Step 0: 换源核心就是把/etc/apt ...

  8. 【转帖】linux 内核分析工具 Dtrace、SystemTap、火焰图、crash等

    << System语言详解 >> 关于 SystemTap 的书. 我们在分析各种系统异常和故障的时候,通常会用到 pstack(jstack) /pldd/ lsof/ tc ...

  9. [转帖]vm内核参数之缓存回收drop_caches

    注:本文分析基于3.10.0-693.el7内核版本,即CentOS 7.4 1.关于drop_caches 通常在内存不足时,我们习惯通过echo 3 > /proc/sys/vm/drop_ ...

  10. [转帖]nacos discovery和config

    微服务和nacos版本都在2.x及之后. 1.discovery用于服务注册,将想要注册的服务注册到nacos中,被naocs发现. pom引入的依赖是: yml配置文件中: 2.config用于获取 ...