题目链接:

Codeforces741D

题目大意:给出一棵树,根为$1$,每条边有一个$a-v$的小写字母,求每个点子树中的一条最长的简单路径使得这条路径上的边上的字母重排后是一个回文串。

显然如果一条路径上的字母重排后是回文串,那么最多有一个字母有奇数个。我们用$2^{22}$的一个二进制来记录有哪些字母有奇数个。剩下的只需要$dsu\ on\ tree$来求每个点的答案即可。对于每个点记录它到根的路径上的字母的二进制状态,显然位于一个点两个不同子树中的点的状态异或起来就是这两个点间路径的二进制状态。开一个桶存每种状态的最大深度然后在对于每个点求答案时依次遍历子树求出最大值即可。注意遍历轻儿子时要先用轻儿子子树中的点更新答案之后再将轻儿子子树中的点的信息加入桶中。

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<bitset>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int cnt[5000000];
int head[500010];
int to[1000010];
int nex[1000010];
int size[500010];
int son[500010];
int val[500010];
int dep[500010];
int tot;
int n;
int x,y;
char ch[2];
int ans[500010];
int tag[500010];
void add(int x,int y)
{
nex[++tot]=head[x];
head[x]=tot;
to[tot]=y;
}
void dfs(int x)
{
size[x]=1;
for(int i=head[x];i;i=nex[i])
{
dep[to[i]]=dep[x]+1;
val[to[i]]^=val[x];
dfs(to[i]);
size[x]+=size[to[i]];
if(size[to[i]]>size[son[x]])
{
son[x]=to[i];
}
}
}
void calc(int x,int anc)
{
ans[anc]=max(ans[anc],cnt[val[x]]+dep[x]-2*dep[anc]);
for(int i=0;i<22;i++)
{
ans[anc]=max(ans[anc],cnt[val[x]^(1<<i)]+dep[x]-2*dep[anc]);
}
for(int i=head[x];i;i=nex[i])
{
calc(to[i],anc);
}
}
void solve(int x,int opt)
{
if(opt==1)
{
cnt[val[x]]=max(dep[x],cnt[val[x]]);
}
else
{
cnt[val[x]]=-1<<30;
}
for(int i=head[x];i;i=nex[i])
{
solve(to[i],opt);
}
}
void dsu_on_tree(int x,int opt)
{
for(int i=head[x];i;i=nex[i])
{
if(to[i]!=son[x])
{
dsu_on_tree(to[i],0);
ans[x]=max(ans[x],ans[to[i]]);
}
}
if(son[x])
{
dsu_on_tree(son[x],1);
ans[x]=max(ans[x],ans[son[x]]);
}
cnt[val[x]]=max(cnt[val[x]],dep[x]);
ans[x]=max(ans[x],cnt[val[x]]-dep[x]);
for(int i=0;i<22;i++)
{
ans[x]=max(ans[x],cnt[val[x]^(1<<i)]-dep[x]);
}
for(int i=head[x];i;i=nex[i])
{
if(to[i]!=son[x])
{
calc(to[i],x);
solve(to[i],1);
}
}
if(!opt)
{
solve(x,-1);
}
}
int main()
{
scanf("%d",&n);
for(int i=2;i<=n;i++)
{
scanf("%d%s",&x,ch);
add(x,i);
val[i]=1<<(ch[0]-'a');
}
dfs(1);
for(int i=0;i<=(1<<22);i++)
{
cnt[i]=-1<<30;
}
dsu_on_tree(1,1);
for(int i=1;i<=n;i++)
{
printf("%d ",ans[i]);
}
}

[Codeforces741D]Arpa's letter-marked tree and Mehrdad's Dokhtar-kosh paths——dsu on tree的更多相关文章

  1. CF 741D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths [dsu on tree 类似点分治]

    D. Arpa's letter-marked tree and Mehrdad's Dokhtar-kosh paths CF741D 题意: 一棵有根树,边上有字母a~v,求每个子树中最长的边,满 ...

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

    题目链接 \(Description\) 给定一棵树,每条边上有一个字符(a~v).对每个节点,求它的子树中一条最长的路径,满足 路径上所有边上的字符可以重新排列成一个回文串.输出其最长长度. \(n ...

  3. CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths——dsu on tree

    题目描述 一棵根为1 的树,每条边上有一个字符(a-v共22种). 一条简单路径被称为Dokhtar-kosh当且仅当路径上的字符经过重新排序后可以变成一个回文串. 求每个子树中最长的Dokhtar- ...

  4. CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths (dsu on tree) 题解

    先说一下dsu算法. 例题:子树众数问题. 给出一棵树,每个点有点权,求每个子树中出现次数最多的数的出现次数. 树的节点数为n,\(n \leq 500000\) 这个数据范围,\(O(n \sqrt ...

  5. codeforces 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\ o ...

  6. [探究] dsu on tree,一类树上离线问题的做法

    dsu on tree. \(\rm 0x01\) 前言\(\&\)技术分析 \(\bold{dsu~on~tree}\),中文别称"树上启发式合并"(虽然我并不承认这种称 ...

  7. dsu on tree (树上启发式合并) 详解

    一直都没出过算法详解,昨天心血来潮想写一篇,于是 dsu on tree 它来了 1.前置技能 1.链式前向星(vector 建图) 2.dfs 建树 3.剖分轻重链,轻重儿子 重儿子 一个结点的所有 ...

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

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  9. 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 思路: 树上启发式合并 从根节点出发到每个位置的每个字符的奇偶性记为每个位 ...

随机推荐

  1. ORM 多表操作查询及增删改查

    ------------------------------------------只有对前途乐观的人,才能不怕黑暗,才能有力量去创造光明.乐观不是目的,而是人生旅途中的一种态度. 多表操作 创建模型 ...

  2. vue better-scroll用法

    滚动位置固定:在vue中通过路由切换页面时组件会自动滚动到顶部,需要监听滚动行为才能让滚动位置固定,better-scroll解决了这个问题. 常用效果:移动端很常见的效果,当滑动右边部分的时候,左边 ...

  3. STL queue用法

    先进先出 #include<iostream> #include<algorithm> #include<cstdio> #include<stack> ...

  4. 关于always块内for循环的执行方式

    //该模块主要用来说明for结构在时序逻辑中的执行方式 :] eq_dly ); integer i; 'b1; always @(posedge clk_1 or negedge nrst) beg ...

  5. 线程中的samaphore信号量及event事件

    一.信号量 samaphore: 在程序中意思为同时允许几个线程运行,比如我们去水上乐园的滑梯玩时,有四个滑梯,每一个滑梯上当没有人在中间玩滑下去时才允许上人,四个滑梯1,2,3,4,同时最多四个人, ...

  6. js处理ajax返回的json数组

    一.json对象和json数组的区别 jsonObject = {} # json对象 jsonArray=[{},{}] # json数组 二.数据处理 前台接收到后台传过来的json数组实际上是一 ...

  7. asp.net mvc 自定义全局过滤器 验证用户是否登录

    一般具有用户模块的系统都需要对用户是否登录进行验证,如果用户登录了就可以继续操作,否则退回用户的登录页面 对于这样的需求我们可以通过自定义一个独立的方法来完成验证的操作,但是这样代码的重复率就大大提高 ...

  8. 容错处理try

    var num = 90; try{ console.log( num + 100 ); consolel.log(aaa); }catch(e){ console.log("如果程序中有异 ...

  9. Java 线程的创建和启动

    Java 使用 Thread 类代表线程,所有的线程对象都必须是 Thread 类或其子类的实例.每个线程的作用是完成一定的任务,实际上就是执行一段程序流(一段顺序执行的代码). Java 使用线程执 ...

  10. VUE.JS 使用axios数据请求时数据绑定时 报错 TypeError: Cannot set property 'xxxx' of undefined 的解决办法

    正常情况下在data里面都有做了定义 在函数里面进行赋值 这时候你运行时会发现,数据可以请求到,但是会报错 TypeError: Cannot set property 'listgroup' of ...