您的位置:首页 > 其它

CF 741 D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

2018-09-27 10:22 441 查看

D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

http://codeforces.com/problemset/problem/741/D

题意:

  一棵根为1 的树,每条边上有一个字符(a-v共22种)。 求每个子树内的最长的路径,使得路径上的边按照一定顺序排列后是回文串。

分析:

  dsu on tree。询问子树信息。

  首先将这22个字符,转化为二进制。a=1,b=10,c=100...如果一条路径可以是回文串,那么要求路径的异或和最多有一个1。所以记录下从根到每个点的异或和,那么一条路径的异或和就是dis[u]^dis[v],lca上面的异或后消失了。

  之后维护每个子树内异或和为x的最大深度是多少。记为f。

  更新答案:按照点分治的思想,先更新不经过根的,然后求出经过根的(更新分成两步,第一步更新答案,第二步更新f数组。防止更新了在子树内部的)。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
#include<cctype>
#include<set>
#include<vector>
#include<queue>
#include<map>
using namespace std;
typedef long long LL;

inline int read() {
int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 500005;

int head
, nxt
, to
, len
, En;
int fa
, siz
, son
, dis
, deth
, ans
;
int f[(1 << 22) + 5];
int Mx, D;

void add_edge(int u,int v,int w) {
++En; to[En] = v; len[En] = w; nxt[En] = head[u]; head[u] = En;
}

void dfs(int u) {
siz[u] = 1;
deth[u] = deth[fa[u]] + 1;
for (int i=head[u]; i; i=nxt[i]) {
int v = to[i];
fa[v] = u;
dis[v] = dis[u] ^ (1 << len[i]);
dfs(v);
siz[u] += siz[v];
if (!son[u] || siz[son[u]] < siz[v]) son[u] = v;
}
}

void add(int u) {
if (f[dis[u]]) Mx = max(Mx, deth[u] + f[dis[u]] - D); // 异或后为0
for (int i=0; i<22; ++i) // 异或后有一个1
if (f[(1 << i) ^ dis[u]]) Mx = max(Mx, deth[u] + f[(1 << i) ^ dis[u]] - D);
}
void Calc(int u) { // 计算答案
add(u);
for (int i=head[u]; i; i=nxt[i]) Calc(to[i]);
}
void upd(int u) {
f[dis[u]] = max(deth[u], f[dis[u]]);
}
void update(int u) { // 更新f数组
upd(u);
for (int i=head[u]; i; i=nxt[i]) update(to[i]);
}
void Clear(int u) {
f[dis[u]] = 0;
for (int i=head[u]; i; i=nxt[i]) Clear(to[i]);
}

void solve(int u,bool c) {
for (int i=head[u]; i; i=nxt[i])
if (to[i] != son[u]) solve(to[i], 0);
if (son[u]) solve(son[u], 1);

D = deth[u] * 2;
for (int i=head[u]; i; i=nxt[i]) Mx = max(Mx, ans[to[i]]); //不经过根的
for (int i=head[u]; i; i=nxt[i])
if (to[i] != son[u]) Calc(to[i]), update(to[i]); // update(u) !!! 先更新答案,在更新f数组,(防止计算到在子树内部的路径)
add(u); upd(u);
ans[u] = Mx;
if (!c) Clear(u), Mx = 0;
}

int main() {
int n = read();
char c[10];
for (int i=2; i<=n; ++i) {
int u = read(); scanf("%s", c);
add_edge(u, i, c[0] - 'a');
}
dfs(1);
solve(1, 1);
for (int i=1; i<=n; ++i) printf("%d ",ans[i]);
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐