Codeforces Round #383 (Div. 1) D
着实难做!
首先,题意,题意不是一棵子树上任意构成!!!
题意:
问的是对应子树v,它上面的简单路径(链),所能构成的最长的回文长度。然后输出对应的1~N的所有以它为子树根结点的最长回文长度(不强制要求经过根结点)。
思路:
首先,我们考虑因为是可以打乱顺序的,所以,如果构成回文,要么有唯一一个符号是出现奇数次的,要么就是没有一个符号出现奇数次,这两个都是可以构成回文的,又因为这里有奇偶,开始往0、1方向上想,若为奇数则为1,若为偶数则为0,岂不就是一个xor的思想了嘛,这里存档。
再者,xor有性质,如果a ^ b == 0则说明a和b加起来一定是个偶数了,如果说a ^ b得到的值在二进制中只有唯一一次出现1,那么它也是满足条件的。这样,情况一的时候我们可以直接知道,情况二考虑奇数唯一时候,我们可以1~22的枚举,复杂度O(22)就是可以的了。
然后,就是维护了,因为这里的信息涉及到了子树的关系上去,可以往Dsu上面想想。我们需要确定子树信息,我们不难知道以某个点作为子树的根节点的时候,它所有子树下的链与他构成回文串的情况。1~22枚举哪一位是奇数,然后现在从原树根节点到目前点的xor值是Xor[u],于是有Xor[u] ^ (1 << i)如果是存在的,我们就可以去更新答案,进行比较了。
然后的话,就是更新这个子树了,这里用Dsu进行优化,将复杂度变为O(N * log(N))。我们对重儿子的答案不做删除,对轻儿子的答案直接更新,更新过程中,我们依然要与答案进行比较,为什么呢?可能将子树的根结点作为链中间的节点进行答案统计,这里的话直接deep[u] + deep[v] - deep[lca] * 2的做法就可以了,更新完成之后删除。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#define _ABS(x, y) ( x > y ? (x - y) : (y - x) )
#define lowbit(x) ( x&( -x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define efs 1e-7
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 5e5 + 7;
inline int _real(int x) { return (1 << x); }
int N, head[maxN], cnt, Xor[1 << 22] = {0};
struct Eddge
{
int nex, to, val;
Eddge(int a=-1, int b=0, int c=0):nex(a), to(b), val(c) {}
}edge[maxN];
inline void addEddge(int u, int v, int val)
{
edge[cnt] = Eddge(head[u], v, val);
head[u] = cnt++;
}
int Wson[maxN], siz[maxN], Wedge[maxN], id[maxN], rid[maxN], tot = 0, its_end[maxN], deep[maxN];
void pre_dfs(int u)
{
id[u] = ++tot;
rid[tot] = u;
siz[u] = 1;
int maxx = 0;
for(int i=head[u], v; ~i; i=edge[i].nex)
{
v = edge[i].to;
Xor[v] = Xor[u] ^ (1 << edge[i].val); //求出每一条简单路径的贡献
deep[v] = deep[u] + 1;
pre_dfs(v);
siz[u] += siz[v];
if(siz[v] > maxx)
{
Wson[u] = v;
Wedge[u] = edge[i].val;
maxx = siz[v];
}
}
its_end[u] = tot;
}
int ans[maxN] = {0}, F[1 << 22] = {0};
bool letter[27] = {false};
void dfs(int u, int op)
{
for(int i=head[u], v; ~i; i=edge[i].nex)
{
v = edge[i].to;
if(v == Wson[u]) continue;
dfs(v, 0);
ans[u] = max(ans[u], ans[v]);
}
if(Wson[u])
{
dfs(Wson[u], 1);
ans[u] = max(ans[u], ans[Wson[u]]);
}
if(F[Xor[u]]) ans[u] = max(ans[u], F[Xor[u]] - deep[u]); //完全相等
for(int i=0; i<22; i++) //最多有一个差别的情况
{
if(F[Xor[u] ^ (1 << i)]) ans[u] = max(ans[u], F[Xor[u] ^ (1 << i)] - deep[u]);
}
F[Xor[u]] = max(F[Xor[u]], deep[u]);
for(int i=head[u], v; ~i; i=edge[i].nex)
{
v = edge[i].to;
if(v == Wson[u]) continue;
for(int j=id[v], w; j<=its_end[v]; j++)
{
w = rid[j];
if(F[Xor[w]]) ans[u] = max(ans[u], F[Xor[w]] + deep[w] - (deep[u] << 1));
for(int k=0; k<22; k++)
{
if(F[Xor[w] ^ (1 << k)]) ans[u] = max(ans[u], F[Xor[w] ^ (1 << k)] + deep[w] - (deep[u] << 1));
}
}
for(int j=id[v], w; j<=its_end[v]; j++)
{
w = rid[j];
F[Xor[w]] = max(F[Xor[w]], deep[w]);
}
}
if(!op)
{
for(int i=id[u]; i<=its_end[u]; i++) F[Xor[rid[i]]] = 0;
}
}
inline void init()
{
cnt = 0;
for(int i=1; i<=N; i++) head[i] = -1;
}
int main()
{
scanf("%d", &N);
init();
int pf;
char s[3];
for(int i=2; i<=N; i++)
{
scanf("%d%s", &pf, s);
addEddge(pf, i, s[0] - 'a');
}
pre_dfs(1);
dfs(1, 0);
for(int i=1; i<=N; i++) printf("%d%c", ans[i], i == N ? '\n' : ' ');
return 0;
}