NC213912 芭芭拉冲鸭~(续)

题目链接

题目

题目描述

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

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

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

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

输入描述

第一行有一个正整数 n 
接下来的 n1  行,每行输入两个正整数 x y  ,代表 x y  之间有一条无向边相连。
接下来一行有一个长度为 n  的字符串,字符串仅由小写字母构成。第 i  个字符表示节点 i  上的字母。
接下来一行是一个正整数 q  ,代表询问次数。

接下来的 q  行,每行两个正整数 x y 

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

(1n,q1000001x,yn) 

输出描述

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

示例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+qlogn)

空间复杂度 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;
}
posted @   空白菌  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源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
点击右上角即可分享
微信分享提示