NC213912 芭芭拉冲鸭~(续)
题目
题目描述
芭芭拉这次来到了一棵字母树,这同样是一棵无根树,每个节点上面有一个小写字母。
芭芭拉想知道,自己从x冲刺到y,从x走到y收集所有字母,选择其中一部分字母组成一个回文串,这个回文串的最大长度是多少?
同样的,芭芭拉冲刺的时候是不能掉头的。
一共有q次询问。每次的询问是独立的(即本次收集字母不影响之后的询问,每次询问时字母都是未被收集状态)。
输入描述
第一行有一个正整数 。
接下来的 行,每行输入两个正整数 和 ,代表 和 之间有一条无向边相连。
接下来一行有一个长度为 的字符串,字符串仅由小写字母构成。第 个字符表示节点 上的字母。
接下来一行是一个正整数 ,代表询问次数。
接下来的 行,每行两个正整数 和 。
(保证输入一定是一棵树)
输出描述
对应每次询问,输出一个正整数,代表回文串的最大长度。
示例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。
题解
知识点:树链剖分,枚举,前缀和。
考虑用树剖,然后用前缀和维护一条树链的各个字母的数量。
每次询问时,求出路径字母数量和后,构造最长的回文串即可:偶数字母直接加,奇数字母只能完整加一次,剩下的只能减 。
时间复杂度
空间复杂度
代码
#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; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/17499358.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
2022-06-23 NC50038 kotori和糖果
2022-06-23 Contest
2022-06-23 NC19115 选择颜色
2022-06-23 NC23046 华华教月月做数学
2022-06-23 NC14731 逆序对
2022-06-23 NC15052 求最值
2022-06-23 NC50999 表达式计算4