https://codeforces.com/contest/1771/problem/D
#include <bits/stdc++.h>
#define ll long long
#define all(a) a.begin(), a.end()
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
using namespace std;
const int N = 2e3 + 10;
/*
题意:给一棵节点带字母的树, 定义s(u, v)时u到v的简单路径上的所有字母按顺序排放的字符串, 求所有s(u, v)中回文子序列长度最大值
解:动态规划
链(一维)上求解(O(n^2)):dp[i][j] = max(dp[i + 1][j], dp[i][j - 1], dp[i + 1][j - 1] + (s[i] == s[j] ? 2 : 0))
树上求解(O(n^2logn)):参考链上求解
若 u, v 的 lca 不为它们其中一个, 则
dp[i][j] = max(dp[fa[u]][v], dp[u][fa[v]], dp[fa[u]][fa[v]] + (s[u] == s[v] ? 2 : 0))
若 u, v 的 lca 不为它们其中一个(令u为lca),
其实就是将 fa[u] 换成是 u 往 v 方向上的第一个节点(也就是向上距离v节点 dep[v] - dp[u] - 1 的那个节点)
*/
int n;
int dep[N], fa[N][21];
vector<int> g[N];
void dfs(int x, int pre, int d)
{
fa[x][0] = pre;
dep[x] = d;
for (auto to : g[x])
if (to != pre)
dfs(to, x, d + 1);
}
int LCA(int u, int v)
{
if (dep[u] > dep[v])
swap(u, v);
int temp = dep[v] - dep[u];
for (ll i = 0; ((1 << i) <= temp); i++)
if ((1 << i) & temp)
v = fa[v][i];
if (u == v)
return u;
for (ll i = log2(n); i >= 0; i--)
{
if (fa[u][i] != fa[v][i])
{
u = fa[u][i];
v = fa[v][i];
}
}
return fa[u][0];
}
void init()
{
for (int i = 1; i <= n; i++)
for (int j = 0; j <= 20; j++)
fa[i][j] = 0;
dfs(1, -1, 0);
for (ll j = 0; (1 << j) <= n; j++)
{
for (ll i = 1; i <= n; i++)
{
if (fa[i][j] < 0)
fa[i][j + 1] = -1;
else
fa[i][j + 1] = fa[fa[i][j]][j];
}
}
}
int find(int x, int d)
{
for (ll i = log2(n); i >= 0; i--)
{
if ((1 << i) <= d)
{
x = fa[x][i];
d -= (1 << i);
}
}
return x;
}
void solve()
{
cin >> n;
for (int i = 1; i <= n; i++)
g[i].clear();
string s;
cin >> s;
s = '?' + s;
for (int i = 1, u, v; i < n; i++)
{
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
if (n == 1)
{
cout << 1 << '\n';
return;
}
init();
vector<vector<pair<int, int>>> v(n);
for (int i = 1; i <= n; i++)
{
for (int j = i; j <= n; j++)
{
int dis = dep[i] + dep[j] - 2 * dep[LCA(i, j)];
v[dis].push_back({i, j});
}
}
vector<vector<int>> dp(n + 1, vector<int>(n + 1));
for (int i = 1; i <= n; i++)
dp[i][i] = 1;
for (auto &[x, y] : v[1])
dp[x][y] = dp[y][x] = (s[x] == s[y] ? 2 : 1);
for (int dis = 2; dis < n; dis++)
{
for (auto &[u, v] : v[dis])
{
if (dep[u] > dep[v])
swap(u, v);
int x = fa[u][0];
if (LCA(u, v) == u)
x = find(v, dep[v] - dep[u] - 1);
dp[u][v] = max(dp[x][v], dp[fa[v][0]][u]);
if (s[u] == s[v])
dp[u][v] = max(dp[u][v], dp[x][fa[v][0]] + 2);
dp[v][u] = dp[u][v];
}
}
int ans = 0;
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
ans = max(ans, dp[i][j]);
cout << ans << '\n';
}
signed main()
{
IOS;
int t = 1;
cin >> t;
while (t--)
solve();
return 0;
}
Hossam and (sub-)palindromic tree(树上LPS问题)
最新推荐文章于 2024-07-14 19:56:17 发布