题目大意:

  给定一个以1为根的树,每条路径上都有一个字符(a~v共22个)询问对于每一个子树内最长的路径上字母经排序后可以形成回文串的最长路径多长

解题思路:

  假定给你一个字符串,如何判定其经打乱能否形成回文串,那就是说所有字符中最多只有一个能出现奇数次,22个字符,可以用2进制表示每个字符出现的次数奇偶性,1为奇0为偶,那么处理出一个点到根节点路径上的异或和(设为xi),如果两个节点i,j的xi=xj那么就说明这两个点的路径上符合要求。

  暴力的思路:暴力搜索一棵树中所有的xi看看有没有相同或差一位的再进行答案更新。

  考虑优化,既然是不同子树中的点,那么就可以用一个数组存起来异或和为x的最大深度maxdeep[x],每次进去找,找完再把整颗子树推进去。这样就是O(n2)

  这样就可以用DSU了,每次处理子树时,最后处理重儿子,非重儿子直接推倒,在更新上层时直接在重儿子版本上构建数组,再重建轻儿子,注意更新答案时要更新为子树最大值,跨字数最大值,返祖链最大值中的最大值。时间复杂度O(nlogn)

  DSU还是十分优秀啊

  代码:

 #include<cstdio>
#include<cstring>
#include<algorithm>
struct pnt{
int hd;
int dp;
int wgt;
int mxs;
int ans;
int xr;
}p[];
struct ent{
int twd;
int lst;
int vls;
}e[];
int n;
int cnt;
char cmd[];
int mxdp[];
void ade(int f,int t,int v)
{
cnt++;
e[cnt].twd=t;
e[cnt].lst=p[f].hd;
e[cnt].vls=v;
p[f].hd=cnt;
}
void Basic_dfs(int x,int f)
{
p[x].dp=p[f].dp+;
p[x].wgt=;
int maxs=-;
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
p[to].xr=p[x].xr^e[i].vls;
Basic_dfs(to,x);
p[x].wgt+=p[to].wgt;
if(maxs<p[to].wgt)
{
maxs=p[to].wgt;
p[x].mxs=to;
}
}
}
void Build_dfs(int x)
{
mxdp[p[x].xr]=std::max(mxdp[p[x].xr],p[x].dp);
for(int i=p[x].hd;i;i=e[i].lst)
Build_dfs(e[i].twd);
}
void Destory_dfs(int x)
{
mxdp[p[x].xr]=;
for(int i=p[x].hd;i;i=e[i].lst)
Destory_dfs(e[i].twd);
}
void Ans_dfs(int x,int a)
{
if(mxdp[p[x].xr])
p[a].ans=std::max(p[a].ans,p[x].dp+mxdp[p[x].xr]-*p[a].dp);
for(int i=;i<;i++)
{
int tmp=<<i;
if(mxdp[p[x].xr^tmp])
p[a].ans=std::max(p[a].ans,p[x].dp+mxdp[p[x].xr^tmp]-*p[a].dp);
}
for(int i=p[x].hd;i;i=e[i].lst)
Ans_dfs(e[i].twd,a);
}
void DSU_dfs(int x,bool hvs)
{
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
if(to==p[x].mxs)
continue;
DSU_dfs(to,false);
p[x].ans=std::max(p[x].ans,p[to].ans);
}
if(p[x].mxs)
{
DSU_dfs(p[x].mxs,true);
p[x].ans=std::max(p[x].ans,p[p[x].mxs].ans);
}
if(mxdp[p[x].xr])
p[x].ans=std::max(p[x].ans,mxdp[p[x].xr]-p[x].dp);
for(int i=;i<;i++)
{
int tmp=<<i;
if(mxdp[p[x].xr^tmp])
p[x].ans=std::max(p[x].ans,mxdp[p[x].xr^tmp]-p[x].dp);
}
mxdp[p[x].xr]=std::max(p[x].dp,mxdp[p[x].xr]);
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
if(to==p[x].mxs)
continue;
Ans_dfs(to,x);
Build_dfs(to);
}
if(hvs)
return ;
Destory_dfs(x);
}
int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++)
{
int x;
scanf("%d",&x);
scanf("%s",cmd);
int tmp=<<(cmd[]-'a');
ade(x,i,tmp);
}
Basic_dfs(,);
DSU_dfs(,true);
for(int i=;i<=n;i++)
printf("%d ",p[i].ans);
puts("");
return ;
}

CF741DArpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(DSU on tree)的更多相关文章

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

    感觉dsu on tree一定程度上还是与点分类似的.考虑求出跨过每个点的最长满足要求的路径,再对子树内取max即可. 重排后可以变成回文串相当于出现奇数次的字母不超过1个.考虑dsu on tree ...

  2. 【CodeForces】741 D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(dsu on tree)

    [题意]给定n个点的树,每条边有一个小写字母a~v,求每棵子树内的最长回文路径,回文路径定义为路径上所有字母存在一种排列为回文串.n<=5*10^5. [算法]dsu on tree [题解]这 ...

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

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

  4. 【cf741】D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(dsu on tree)

    传送门 题意: 给出一颗以\(1\)为根的有根树,树边带有一个字符(\(a\)~\(v\))的信息. 输出对于每个结点,其子树内最长的简单路径并且满足边上的字符能够组成回文串. 思路: 显然最终的答案 ...

  5. 【CF741D】Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(dsu on tree)

    题意:我们称一个字符串为周驿东串当且仅当重排它的字符可以组成一个回文串. 给出一个n个点的有根树,根为1,每条边上有一个从a到v的字符,求每个点的子树中所有简单路径可以组成的周驿东串中的最长长度. n ...

  6. 【CF600E】Lomsat gelral(dsu on tree)

    [CF600E]Lomsat gelral(dsu on tree) 题面 洛谷 CF题面自己去找找吧. 题解 \(dsu\ on\ tree\)板子题 其实就是做子树询问的一个较快的方法. 对于子树 ...

  7. 【Luogu U41492】树上数颜色——树上启发式合并(dsu on tree)

    (这题在洛谷主站居然搜不到--还是在百度上偶然看到的) 题目描述 给一棵根为1的树,每次询问子树颜色种类数 输入输出格式 输入格式: 第一行一个整数n,表示树的结点数 接下来n-1行,每行一条边 接下 ...

  8. CF375D Tree and Queries(dsu on tree)

    思路 dsu on tree的板子,可惜人傻把 for(int i=fir[u];i;i=nxt[i]) 打成 for(int i=fir[u];i<=n;i++) 调了两个小时 这题要求维护& ...

  9. CF600E Lomsat gelral(dsu on tree)

    dsu on tree跟冰茶祭有什么关系啊喂 dsu on tree的模板题 思想与解题过程 类似树链剖分的思路 先统计轻儿子的贡献,再统计重儿子的贡献,得出当前节点的答案后再减去轻儿子对答案的贡献 ...

随机推荐

  1. Android设计模式(十二)--抽象工厂模式

    问题: 抽象工厂模式,是一个,狠恶心的模式,那么这个模式在Android有没实用到过呢? 1.定义: 抽象工厂模式:为创建一组相关或者是相互依赖的对象提供一个接口,而不须要指定他们的详细类. 2.使用 ...

  2. vue12 循环添加重复数据

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. Mysql基础部分,针对以后python使用

    #redis 非关系型数据库#mysql 关系型数据库 表与表之间有数据关系 Oracle Mysql SqlServer DB2#多张表组合在一起就是数据库#冗余 存储两倍数据 可以使系统速度更快 ...

  4. ADO.NET数据读取封装

    public class sqlserver { //private string sqlstr = System.ConfigurationManager.ConnectionStrings[&qu ...

  5. 洛谷P2633 Count on a tree

    题目描述 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个 ...

  6. C++中explicit关键字作用

    explicit是c++中不太常用的一个关键字,其作用是用于修饰构造函数,告诉编译器定义对象时不做隐式转换. 举例说明: include <iostream> include <st ...

  7. JavaScript Debug调试技巧

    收藏于:https://blog.fundebug.com/2017/12/04/javascript-debugging-for-beginners/

  8. 织梦DedeCMS判断简略标题为空时则显示完整标题

    使用织梦DedeCMS系统程序开发网站中,我们会遇到很多因网页版面设计限定的宽度,使文章标题需要进行字数限制,通常做法是在a标签中加入一个title属性,让鼠标放上去的时候显示完整标题.但是标题被剪裁 ...

  9. 判断控件的CGRect是否重合,获取控件的最大XY值

    判断给定的点是否被一个CGRect包含: BOOL contains = CGRectContainsPoint(CGRect rect, CGPoint point); 判断一个CGRect是否和另 ...

  10. Lua刚開始学习的人(一)--Lua 简单教学

    近期因为工作原因.临时木有<Oracle起步学习>续集.领导知道学习下Lua脚本语言.看了一周了.趁热打铁,留下点实用的东西吧. 本系列会主要针对宿主语言为 Delphi,原理都是一样的, ...