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

重新排列后组成回文串意味着路径上出现奇数次的最多1个,那么可以\(dsu\ on\ tree\)搞一下了。。。

/*
  mail: [email protected]
  author: MLEAutoMaton
  This Code is made by MLEAutoMaton
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<iostream>
using namespace std;
#define ll long long
#define re register
#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
inline int gi(){
    int f=1,sum=0;char ch=getchar();
    while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    return f*sum;
}
const int N=500010;
int n,dep[N],siz[N],son[N],front[N],cnt,dfn[N],Time,low[N],dis[N],id[N],ans[N],mx,f[1<<22];
struct node{int to,nxt,w;}e[N];
void Add(int u,int v,int w){e[++cnt]=(node){v,front[u],w};front[u]=cnt;}
void dfs(int u,int ff){
    id[dfn[u]=++Time]=u;
    siz[u]=1;dep[u]=dep[ff]+1;
    for(int i=front[u];i;i=e[i].nxt){
        int v=e[i].to;dis[v]=dis[u]^e[i].w;
        dfs(v,u);siz[u]+=siz[v];
        if(siz[v]>siz[son[u]])son[u]=v;
    }
    low[u]=Time;
}
void dfs(int u,int ff,int kp){
    for(int i=front[u];i;i=e[i].nxt){
        int v=e[i].to;if(v==son[u])continue;
        dfs(v,u,0);ans[u]=max(ans[u],ans[v]);
    }
    if(son[u])dfs(son[u],u,1),ans[u]=max(ans[u],ans[son[u]]);
    if(f[dis[u]])ans[u]=max(ans[u],f[dis[u]]-dep[u]);
    for(int i=0;i<22;i++)
        if(f[dis[u]^(1<<i)])ans[u]=max(ans[u],f[dis[u]^(1<<i)]-dep[u]);
    f[dis[u]]=max(f[dis[u]],dep[u]);
    for(int E=front[u];E;E=e[E].nxt){
        int v=e[E].to;if(v==son[u])continue;
        for(int i=dfn[v];i<=low[v];i++){
            if(f[dis[id[i]]])ans[u]=max(ans[u],f[dis[id[i]]]+dep[id[i]]-(dep[u]<<1));
            for(int j=0;j<22;j++)
                if(f[dis[id[i]]^(1<<j)])
                    ans[u]=max(ans[u],f[dis[id[i]]^(1<<j)]+dep[id[i]]-(dep[u]<<1));
        }
        for(int i=dfn[v];i<=low[v];i++)
            f[dis[id[i]]]=max(f[dis[id[i]]],dep[id[i]]);
    }
    if(!kp)for(int i=dfn[u];i<=low[u];i++)f[dis[id[i]]]=0;
}
int main(){
    n=gi();
    for(int i=2;i<=n;i++){
        int F=gi();char ch=getchar();while(ch<'a' || ch>'v')ch=getchar();
        Add(F,i,1<<(ch-'a'));
    }
    dfs(1,1);dfs(1,1,1);
    for(int i=1;i<=n;i++)printf("%d%c",ans[i],i==n?'\n':' ');
    return 0;
}

原文地址:https://www.cnblogs.com/mle-world/p/11146032.html

时间: 2024-10-31 08:39:31

CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths的相关文章

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

题目链接:Arpa's letter-marked tree and Mehrdad's Dokhtar-kosh paths 第一次写\(dsu\ on\ tree\),来记录一下 \(dsu\ on\ tree\)主要维护子树信息,往往可以省掉一个数据结构的启发式合并.大体思路如下: 轻重链路径剖分之后,对每个点先递归处理他的所有轻儿子,每次处理完轻儿子之后把这棵子树的信息清空.最后再来处理重孩子,重儿子的信息就可以不用清空了.由于我们是用一个全局数组来记录信息的,重儿子子树的信息就仍然保留

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

D - Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths 思路: 树上启发式合并 从根节点出发到每个位置的每个字符的奇偶性记为每个位置的状态,每次统计一下每个状态的最大深度 为了保证链经过当前节点u,我们先计算每个子树的答案,再更新子树状态对深度的贡献. 代码: #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize(4) #include<bit

「CF741D」Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

传送门 Luogu 解题思路 考虑把22个字符状压下来,易知合法情况就是状态中之多有一个1,这个可以暴力一点判断23次. 然后后就是 dsu on the tree 了. 细节注意事项 咕咕咕 参考代码 #include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <cctype> #i

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

Description 以\(1\) 为根 的 \(n\) 个节点的树,每条边有一个颜色 \(x\),求每一个点的子树内的好的路径的最长长度 一条路径被定义为好的当且仅当把所有经过的边的字母经过排列之后可以变成回文 题面 Solution 理解了一下 \(dsu\,on\,tree\),相比普通的启发式,省去了高级的数据结构,并省下了大量空间 好的路径实际上就是出现奇数次的字母不多于一个,字符集只有 \(22\),可以状压起来 对于一条路径的异或和实际上可以看成 \(dis[x]\)^\(dis

Codeforces.741D.Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(dsu on tree 思路)

题目链接 \(Description\) 给定一棵树,每条边上有一个字符(a~v).对每个节点,求它的子树中一条最长的路径,满足 路径上所有边上的字符可以重新排列成一个回文串.输出其最长长度. \(n\leq 5\times10^5\). \(Solution\) 可以构成回文串,即要么所有字符都出现了偶数次,要么有一个出现了奇数次.其余都出现了偶数次. 转化为异或!把每个字符c(0~21)映射到1<<c上去. 令\(s[x]\)表示根节点到\(x\)路径上边权的异或和.那么路径\((u,v)

Arpa&#39;s weak amphitheater and Mehrdad&#39;s valuable Hoses CodeForces - 742D

Just to remind, girls in Arpa's land are really nice. Mehrdad wants to invite some Hoses to the palace for a dancing party. Each Hos has some weight wi and some beauty bi. Also each Hos may have some friends. Hoses are divided in some friendship grou

【学习笔记】dsu on tree

我也不知道为啥这要起这名,完完全全没看到并查集的影子啊-- 实际上原理就是一个树上的启发式合并. 特点是可以在$O(nlogn)$的时间复杂度内完成对无修改的子树的统计,复杂度优于莫队算法. 局限性也很明显:1.不能支持修改  2.只能支持子树统计,不能链上统计.(链上统计你不能直接树剖吗?) 那么它是怎么实现的呢?首先有一个例子:树上每个节点都有一个颜色(那么一定是蓝色), 求每个节点的子树上有多少颜色为k的节点.(每个节点的k不一定相同) $O(n^2)$的算法非常好想,以每个点为起点dfs

树上启发式合并 (dsu on tree)

这个故事告诉我们,在做一个辣鸡出题人的比赛之前,最好先看看他发明了什么新姿势= =居然直接出了道裸题 参考链接: http://codeforces.com/blog/entry/44351(原文) http://blog.csdn.net/QAQ__QAQ/article/details/53455462 这种技巧可以在O(nlogn)的时间内解决绝大多数的无修改子树询问问题. 例1 子树颜色统计 有一棵n个点的有根树,根为1,每个点有一个1~n的颜色,对于每一个点给了一个数k,要询问这个子树

dsu on tree(树上启发式合并)

简介 对于一颗静态树,O(nlogn)时间内处理子树的统计问题.是一种优雅的暴力. 算法思想 很显然,朴素做法下,对于每颗子树对其进行统计的时间复杂度是平方级别的.考虑对树进行一个重链剖分.虽然都基于重链剖分,但不同于树剖,我们维护的不是树链. 对于每个节点,我们先处理其轻儿子所在子树,轻子树在处理完后消除其影响.然后处理重儿子所在子树,保留其贡献.然后再暴力跑该点的轻子树,统计该点子树的最终答案.如果该点子树是轻子树,则消除该子树的影响,否则保留.用代码描述的话,大概是这个流程: void d