【dsu on tree】Codeforces741D[Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths]题解

题目概述

给出一棵 n 个节点的树,边权是小写字母( a v ),若一条链上的小写字母可以打乱排列成回文则称该链满足条件。求每个节点子树中最长的满足条件的链。

解题报告

询问子树不修改果断上dsu on tree。能打乱排列成回文说明至多只有一个字母出现了奇数次,因为字母只有 22 个,所以位运算异或就可以快速判断。至于求答案……因为dsu on tree是大暴力,所以瞎搞就行了……

示例程序

#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
const int maxn=500000,maxs=1<<22;

int n,si[maxn+5],dep[maxn+5],sum[maxn+5],SH[maxn+5];
int E,lnk[maxn+5],son[maxn+5],nxt[maxn+5],w[maxn+5];
int now,MAX,MD[maxs+5],ans[maxn+5];bool vis[maxn+5];

#define Add(x,y,z) son[++E]=(y),w[E]=(z),nxt[E]=lnk[x],lnk[x]=E
inline char getlwr() {char ch=getchar();while (!islower(ch)) ch=getchar();return ch;}
void HLD(int x)
{
    si[x]=1;
    for (int j=lnk[x];j;j=nxt[j])
    {
        dep[son[j]]=dep[x]+1;sum[son[j]]=sum[x]^(1<<w[j]);
        HLD(son[j]);si[x]+=si[son[j]];
        if (si[son[j]]>si[SH[x]]) SH[x]=son[j];
    }
}
inline void getMAX(int x)
{
    if (MD[sum[x]]) MAX=max(MAX,dep[x]+MD[sum[x]]-(now<<1));
    for (int j=0;j<22;j++) if (MD[sum[x]^(1<<j)])
        MAX=max(MAX,dep[x]+MD[sum[x]^(1<<j)]-(now<<1));
}
void Update(int x) {getMAX(x);for (int j=lnk[x];j;j=nxt[j]) Update(son[j]);}
inline void Fix(int x) {if (dep[x]>MD[sum[x]]) MD[sum[x]]=dep[x];}
void Insert(int x) {Fix(x);for (int j=lnk[x];j;j=nxt[j]) Insert(son[j]);}
void Delete(int x) {MD[sum[x]]=0;for (int j=lnk[x];j;j=nxt[j]) Delete(son[j]);}
void Solve(int x,bool fl=true)
{
    for (int j=lnk[x];j;j=nxt[j]) if (son[j]!=SH[x]) Solve(son[j],false);
    if (SH[x]) Solve(SH[x],true);now=dep[x];
    for (int j=lnk[x];j;j=nxt[j]) ans[x]=max(ans[x],ans[son[j]]);
    for (int j=lnk[x];j;j=nxt[j]) if (son[j]!=SH[x])
        Update(son[j]),Insert(son[j]);
    getMAX(x);Fix(x);ans[x]=max(ans[x],MAX);if (!fl) Delete(x),MAX=0;
}
int main()
{
    freopen("program.in","r",stdin);
    freopen("program.out","w",stdout);
    scanf("%d",&n);for (int i=2,x;i<=n;i++) scanf("%d",&x),Add(x,i,getlwr()-'a');
    HLD(1);Solve(1);for (int i=1;i<=n;i++) printf("%d ",ans[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值