题目大意:

  给定一个以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. Java接口源码--System和应用程序进程间通信

    本文參考<Android系统源代码情景分析>.作者罗升阳 一.架构代码: ~/Android/frameworks/base/core/java/android/os ----IInter ...

  2. 剑指offer—java版本实现

    终于完成了全部!所有的心累这时候都觉得很值得啊!爽! https://github.com/xurui1995/Sword-pointing-to-offer

  3. BZOJ 1230 Usaco2008 Nov 开关灯 线段树

    思路: 用线段树模拟题中的操作就好 (标记异或 长度=区间总长度-当前已开灯的长度) //By SiriusRen #include <cstdio> using namespace st ...

  4. c# 导出excel格式xlsx

    string sb="";//sql字符串 AttachmentConfigSection configSection = ConfigurationManager.GetSect ...

  5. vue.js 第一课:实例化vue

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

  6. 安装个wampserver 环境 执行php

    php代码执行要有相关环境. 在这里推荐一个环境工具.wampserver :内置了下面工具: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5 ...

  7. Oracle-02-数据库概述

    一.数据库用途 用于存放数据的软件 当中Application server重要,将数据存在表中每一个表关系就能够反映不同表之间数据的关系,比方淘宝用户注冊.商品买卖等数据存在操作系统的目录中,不便于 ...

  8. js---06函数传参数

    <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content ...

  9. 通过js动态创建button

    通过js动态创建button 一.实例描述 通过JS的DOM对象,实现元素的动态创建. 二.效果 三.代码 <!DOCTYPE html> <html lang="zh-c ...

  10. Linux下MySQL导入导出数据库

    linux下 一.导出数据库用mysqldump命令(注意mysql的安装路径,即此命令的路径):1.导出数据和表结构:mysqldump -u用户名 -p密码 数据库名 > 数据库名.sql# ...