Codeforces 741D dsu on tree

题意

传送门 Codeforces 741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

题解

若某条路径的字符可以构成回文串,则至多一个字符数量为奇数,那么关注字符的奇偶性即可。设字符集的规模为 B B B,对字符集的奇偶性进行状态压缩,满足条件的两个字符集状态异或结果至多存在一个 1 1 1。若某个字符集的状态, O ( B ) O(B) O(B) 即可枚举满足条件的另一个状态。

dsu on tree 维护子树中各个节点字符集状态对应的最大深度,统计经过子树根节点的最长路径,最后用子孙节点的最长路径向上更新答案即可。总时间复杂度 O ( B N log ⁡ N ) O(BN\log N) O(BNlogN)

#include <bits/stdc++.h>
using namespace std;
#define pb push_back
const int MAXN = 5E5 + 5, B = 22, SZ = 1 << B, _INF = 0xc0c0c0c0;
int N, dep[MAXN], sz[MAXN], a[MAXN];
int rec[SZ], res[MAXN], cur;
struct edge
{
    int to, c;
};
vector<edge> G[MAXN];

void _max(int &x, int y) { x = max(x, y); }

void pdfs(int v, int d, int s)
{
    dep[v] = d, sz[v] = 1, a[v] = s;
    for (auto &e : G[v])
        pdfs(e.to, d + 1, s ^ (1 << e.c)), sz[v] += sz[e.to];
}

void count(int v, int p, bool rt)
{
    if (!rt)
    {
        for (auto &e : G[v])
            count(e.to, p, 0);
    }
    _max(cur, dep[v] + rec[a[v]] - 2 * dep[p]);
    for (int i = 0; i < B; ++i)
    {
        int t = a[v] ^ (1 << i);
        _max(cur, dep[v] + rec[t] - 2 * dep[p]);
    }
}

void add(int v)
{
    _max(rec[a[v]], dep[v]);
    for (auto &e : G[v])
        add(e.to);
}

void del(int v)
{
    rec[a[v]] = _INF;
    for (auto &e : G[v])
        del(e.to);
}

void dfs(int v, bool keep)
{
    int mx = -1, ch = -1;
    for (auto &e : G[v])
        if (sz[e.to] > mx)
            mx = sz[e.to], ch = e.to;
    for (auto &e : G[v])
        if (e.to != ch)
            dfs(e.to, 0);
    if (ch != -1)
        dfs(ch, 1);
    cur = 0;
    for (auto &e : G[v])
        if (e.to != ch)
            count(e.to, v, 0), add(e.to);
    count(v, v, 1);
    _max(rec[a[v]], dep[v]);
    res[v] = cur;
    if (!keep)
        del(v);
}

void get_res(int v)
{
    for (auto &e : G[v])
    {
        get_res(e.to);
        res[v] = max(res[v], res[e.to]);
    }
}

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> N;
    for (int i = 1; i < N; ++i)
    {
        int p;
        char c;
        cin >> p >> c;
        G[p - 1].pb({i, c - 'a'});
    }
    pdfs(0, 0, 0);
    memset(rec, 0xc0, sizeof(rec));
    dfs(0, 0);
    get_res(0);
    for (int i = 0; i < N; ++i)
        cout << res[i] << (i + 1 == N ? '\n' : ' ');
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值