题目大意:
一棵根为1 的树,每条边上有一个字符( a − v a−v a−v共22种)。 一条简单路径被称为Dokhtar−kosh当且仅当路径上的字符经过重新排序后可以变成一个回文串。 求每个子树中最长的Dokhtar−kosh路径的长度。
解题思路:
首先我们观察一下,字母只有22种,我们可以用状态压缩去表示字符串的表示方式?
1.什么状态是合法的我们知道回文串奇数个字符只能个数只能是一种,或者全部都是偶数个的字符串。
2.那么我们就可以用异或去维护这个信息,我知道一个数异或了偶数次之后就是0,奇数次就是1,那么就异或值是
2
i
2^i
2i
3.对于求出每个子树的答案,这很明显是树上启发式合并。
我们看看要维护那些信息?
3.1 首先我们先预处理出从每个点从根节点路径上整个的异或和
3.2 首先我们知道对于每个点我们先暴力统计答案,更新答案,然后再递归下去求重儿子树启的常规操作
3.3 对于轻儿子我们可以暴力合并答案到重子树,
首先我们分类讨论求:
1)如果是异或和为0,那么重子树里面肯定有轻子树一样的路径这样异或才为0;
2)如果是异或和为
2
i
2^i
2i 那么我们可以暴力循环0到22给它异或上
2
i
2^i
2i
因
为
这
是
边
权
,
所
以
我
们
要
注
意
我
们
上
面
统
计
的
都
是
两
颗
子
树
之
间
的
路
径
因为这是边权,所以我们要注意我们上面统计的都是两颗子树之间的路径
因为这是边权,所以我们要注意我们上面统计的都是两颗子树之间的路径
但
是
我
们
知
道
这
个
路
径
可
以
是
一
条
直
链
,
那
么
我
们
还
要
统
计
一
下
是
直
链
的
情
况
但是我们知道这个路径可以是一条直链,那么我们还要统计一下是直链的情况
但是我们知道这个路径可以是一条直链,那么我们还要统计一下是直链的情况
#include <bits/stdc++.h>
using namespace std;
const int maxn = 4e6 + 10;
struct node {
int nxt, to, val;
}edge[maxn];
int head[maxn], cnt;
inline void add(int from, int to, int val) {
edge[cnt] = {head[from],to,val-'a'};
head[from] = cnt ++;
}
int n;
int siz[maxn], son[maxn], depth[maxn];
int state[maxn << 1];
void find_son(int u, int fa) {
siz[u] = 1;
depth[u] = depth[fa] + 1;
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].to;
if(v == fa) continue;
state[v] = (state[u] ^ (1ll << edge[i].val));//统计路径异或和
find_son(v,u);
siz[u] = siz[u] + siz[v];
if(son[u] == 0 || siz[son[u]] < siz[v])
son[u] = v;//找重子树
}
}
int root_son;//
int ans[maxn];
int state_has[maxn << 2];//存的是每个异或和最大深度是多少
int updep, maxx;
void dsu(int u, int fa) {
if(state_has[state[u]]) //如果存在一样的异或和路径才转移
maxx = max(maxx,state_has[state[u]] + depth[u] - updep);//因为我们只考虑在这个子树内部肯定要减掉上的深度
for(int i = 0; i <= 22; ++ i)//暴力枚举奇数
if(state_has[state[u] ^ (1ll << i)])
maxx = max(maxx, state_has[state[u] ^ (1ll << i)] + depth[u] - updep);
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].to;
if(v == fa || v == root_son) continue;
dsu(v,u);
}
}
void update(int u, int fa, int op) {
if(op == 1) {
state_has[state[u]] = max(state_has[state[u]],depth[u]);
}
else
state_has[state[u]] = 0;
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].to;
if(v == fa || v == root_son) continue;
update(v,u,op);
}
}
void dfs(int u, int fa, int keep) {
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].to;
if(v == fa || v == son[u]) continue;
dfs(v,u,0);
ans[u] = max(ans[v],ans[u]);
}
if(son[u]) {
dfs(son[u],u,1);
root_son = son[u];
ans[u] = max(ans[root_son],ans[u]);
}
updep = depth[u] * 2;
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].to;
if(v == fa || v == root_son) continue;
dsu(v,u);
update(v,u,1);
}
if(state_has[state[u]]) maxx = max(maxx,state_has[state[u]] - depth[u]);
for(int i = 0; i <= 22; ++ i)
if(state_has[state[u] ^ (1ll << i)])
maxx = max(maxx,state_has[state[u] ^ (1ll << i)] - depth[u]);
state_has[state[u]] = max(state_has[state[u]],depth[u]);
ans[u] = max(maxx,ans[u]);
root_son = 0;
if(!keep) {
update(u,fa,-1);
maxx = updep = 0;
}
}
int main() {
memset(head,-1,sizeof(head));
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
//..............................
cin >> n;
for(int i = 2; i <= n; ++ i) {
int a; char b;
cin >> a >> b;
add(a,i,(int)b);
add(i,a,(int)b);
}
find_son(1,0);
dfs(1,0,0);
for(int i = 1; i <= n; ++ i)
cout << ans[i] << " ";
return 0;
}