#### D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths
[CF741D](http://codeforces.com/contest/741/problem/D)
题意:
一棵有根树,边上有字母a~v,求每个子树中最长的边,满足这个边上的所有字母重拍后可以构成回文


发明者自己出的题...orz

由于本来知道就是dsu on tree,所以还是想出来了

首先点分治是没法做了,这是有根树

写成二进制,两条链合起来构成回文\(\rightarrow\)异或和为0或者只有一位是1

一开始困惑于只处理到当前根的异或和的话,随着当前根的变化异或值会变

然后发现我们可以处理到根的异或和,两条链异或之后\(lca\)之上的部分正好没有了

用\(f[i]\)记录到根的异或和为\(i\)的最大深度

进行dsu on tree

当前子树的答案先\(max\)一下孩子的答案,然后类似于点分治处理经过当前根的路径

和点分治一样,一个一个轻儿子处理,先更新答案再更新信息\(f\)

如果当前是父亲的轻儿子,那么要清空\(f\)的信息

说一下起初的错误:

  1. 单独用了一个\(g\)记录轻儿子,这是不对的,因为当前的子树要么是重儿子,应该一直保留;要么是轻儿子,到时候全清除就可以了。
  2. 一定不能整体操作重儿子的信息,要不然复杂度就不对了
  3. 这里有一个\(trick\),因为有根树处理一棵子树我们可以提前搞出\(dfs\)序就不用每次\(dfs\)了,常数优化显著
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
#define MP make_pair
#define fir first
#define sec second
const int N=5e5+5, M=1e7+5;
int read(){
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
return x*f;
} int n, x;
char s[5];
struct edge{int v, ne, c;}e[N<<1];
int cnt, h[N];
inline void ins(int u, int v, int c) {
e[++cnt]=(edge){v, h[u], c}; h[u]=cnt;
} int Xor[N], dfc, ver[N];
pii dfn[N];
void dfsPre(int u) {
dfn[u].fir = ++dfc; ver[dfc] = u;
for(int i=h[u];i;i=e[i].ne) Xor[e[i].v] = Xor[u]^e[i].c, dfsPre(e[i].v);
dfn[u].sec = dfc;
} int size[N], mx[N], deep[N];
void dfs(int u) {
size[u]=1;
for(int i=h[u];i;i=e[i].ne) {
deep[e[i].v] = deep[u]+1;
dfs(e[i].v);
size[u] += size[e[i].v];
if(size[e[i].v] > size[mx[u]]) mx[u] = e[i].v;
}
} int ans[N], f[M];
void dfs(int u, int keep) {
int &cur = ans[u];
for(int i=h[u];i;i=e[i].ne)
if(e[i].v != mx[u]) dfs(e[i].v, 0), cur = max(cur, ans[e[i].v]);
if(mx[u]) dfs(mx[u], 1), cur = max(cur, ans[mx[u]]); int now = Xor[u], d = deep[u];
if(f[now]) cur = max(cur, f[now] - d);
for(int i=0; i<=21; i++)
if(f[now^(1<<i)]) cur = max(cur, f[now^(1<<i)] - d);
f[now] = max(f[now], d); for(int i=h[u];i;i=e[i].ne) if(e[i].v != mx[u]) {
int l = dfn[e[i].v].fir, r = dfn[e[i].v].sec;
for(int j=l; j<=r; j++) {
int x = ver[j], now = Xor[x];
if(f[now]) cur = max(cur, f[now] + deep[x] - (d<<1));
for(int i=0; i<=21; i++)
if(f[now^(1<<i)]) cur = max(cur, f[now^(1<<i)] + deep[x] - (d<<1));
} for(int j=l; j<=r; j++)
f[ Xor[ver[j]] ] = max(f[ Xor[ver[j]] ], deep[ver[j]]);
} if(!keep) {
int l = dfn[u].fir, r = dfn[u].sec;
for(int j=l; j<=r; j++) f[ Xor[ver[j]] ] = 0;
}
}
int main() {
//freopen("in","r",stdin);
n=read();
for(int i=2; i<=n; i++) x=read(), scanf("%s",s), ins(x, i, 1<<(s[0]-'a') );
dfsPre(1);
deep[1]=1; dfs(1);
dfs(1, 0);
for(int i=1; i<=n; i++) printf("%d ",ans[i]);
}

这里是没用dfs序的版本

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
#define MP make_pair
#define fir first
#define sec second
const int N=5e5+5, M=1e7+5;
int read(){
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
return x*f;
} int n, x;
char s[5];
struct edge{int v, ne, c;}e[N<<1];
int cnt, h[N];
inline void ins(int u, int v, int c) { //printf("ins %d %d %d\n",u,v,c);
e[++cnt]=(edge){v, h[u], c}; h[u]=cnt;
} int Xor[N];
void dfsXor(int u) {
for(int i=h[u];i;i=e[i].ne) Xor[e[i].v] = Xor[u]^e[i].c, dfsXor(e[i].v);
} int size[N], mx[N], deep[N], big[N];
void dfs(int u) {
size[u]=1;
for(int i=h[u];i;i=e[i].ne) {
deep[e[i].v] = deep[u]+1;
dfs(e[i].v);
size[u] += size[e[i].v];
if(size[e[i].v] > size[mx[u]]) mx[u] = e[i].v;
}
} int ans[N], f[M];
void update(int u, int &ans, int d) {
int now = Xor[u];
if(f[now]) ans = max(ans, f[now] + deep[u] - 2*d);
for(int i=0; i<=21; i++) {
int t = now^(1<<i);
if(f[t]) ans = max(ans, f[t] + deep[u] - 2*d);
} for(int i=h[u];i;i=e[i].ne) if(!big[e[i].v]) update(e[i].v, ans, d);
}
void merge(int u) {
int now = Xor[u];
f[now] = max(f[now], deep[u]); for(int i=h[u];i;i=e[i].ne) if(!big[e[i].v]) merge(e[i].v);
}
void clear(int u) {
int now = Xor[u];
f[now] = 0; for(int i=h[u];i;i=e[i].ne) if(!big[e[i].v]) clear(e[i].v);
}
void dfs(int u, int keep) { //printf("dfs %d %d mx %d\n",u,keep,mx[u]);
for(int i=h[u];i;i=e[i].ne)
if(e[i].v != mx[u]) dfs(e[i].v, 0), ans[u] = max(ans[u], ans[e[i].v]);
if(mx[u]) dfs(mx[u], 1), big[mx[u]]=1, ans[u] = max(ans[u], ans[mx[u]]); int now = Xor[u], d = deep[u];
if(f[now]) ans[u] = max(ans[u], f[now] + deep[u] - 2*d);
for(int i=0; i<=21; i++) {
int t = now^(1<<i);
if(f[t]) ans[u] = max(ans[u], f[t] + deep[u] - 2*d);
}
f[now] = max(f[now], d); for(int i=h[u];i;i=e[i].ne)
if(e[i].v != mx[u]) update(e[i].v, ans[u], deep[u]), merge(e[i].v); big[mx[u]]=0;
if(!keep) clear(u);
}
int main() {
//freopen("in","r",stdin);
n=read();
for(int i=2; i<=n; i++) x=read(), scanf("%s",s), ins(x, i, 1<<(s[0]-'a') );
dfsXor(1);
//puts("");for(int i=1; i<=n; i++) printf("Xor %d %d\n",i,Xor[i]);puts("");
deep[1]=1; dfs(1);
dfs(1, 0);
for(int i=1; i<=n; i++) printf("%d ",ans[i]);
}

CF 741D. Arpa’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 思路)

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

  2. [Codeforces741D]Arpa's letter-marked tree and Mehrdad's Dokhtar-kosh paths——dsu on tree

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

  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. codeforces 741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(启发式合并)

    codeforces 741D Arpa's letter-marked tree and Mehrdad's Dokhtar-kosh paths 题意 给出一棵树,每条边上有一个字符,字符集大小只 ...

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

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

随机推荐

  1. 关于JAVA实现二维码以及添加二维码LOGO

    今天在公司,完成了之前的任务,没有什么事做,就想鼓捣一下二维码,因为之前没有接触过,我就去翻看了几本书,也基本完成了二维码的实现,以及添加二维码的LOGO. 现在绘制二维码一般都使用的是谷歌的zxin ...

  2. c#简单操作MongoDB_2.4

    一.MongoDB的安装 MongoDb在windows下的安装与以auth方式启用服务 二.下载驱动 使用nuget搜索“mongodb”,下载“MongoDB.Driver”(这是官方推荐的一个驱 ...

  3. java web开发中遇到的问题及解决方案(个人学习日志,持续更新)

    转:http://blog.csdn.net/ducexu/article/details/7529613 2012.05.02   星期三 1.问题:导入的新工程,名字上出现感叹号. 原因:工程的j ...

  4. VS2008 如何将Release版本设置可以调试的DEBUG版本

    VS2008 如何将Release版本设置可以调试的DEBUG版本 只需设置三个部分: 项目->属性->C/C++->General->Debug Information Fo ...

  5. [国嵌笔记][012][GCC程序编译]

    GCC特点 GCC(GUN C Compiler)是GUN推出的功能强大.性能优越的多平台编译器.其执行效率与一般编译器相比平均效率要高20%~30%. GCC基本用法 gcc [options] f ...

  6. 浅析@Deprecated,调用方法时出现横线划掉样式

    Deprecated 这个注释是一个标记注释.所谓标记注释,就是在源程序中加入这个标记后,并不影响程序的编译,但有时编译器会显示一些警告信息. 那么Deprecated注释是什么意思呢?如果你经常使用 ...

  7. jquery1.8 在IE8 下面报错:对象不支持此属性或方法 return b.getAttribute("id")===a

    jquery1.8 在IE8 下面报错: 对象不支持此属性或方法 调试发现是下面这一行报错: 在IE8下面报错,在chrome和firefox都是好的. 实在找不到原因,最后把源码改成下面这样: 没有 ...

  8. 国寿e店/人寿云参会云助理,不去公司就能刷脸考勤打卡?

    自从2017年3月平安保险公司实行E行销打卡考勤以来,保险增员迅猛增加,保险业绩也随之水涨船高.年底开始中国人寿保险也陆续开始实行app考勤,有些需要连接公司指定WiFi,或在指定地点方可打卡考勤.不 ...

  9. 解决DEDECMS Call to undefined function dede_htmlspecialchars()

    作者:DEDECMS建站网 关注: 3610 时间:2015-11-18 16:39 内容详情 以下内容您可能感兴趣: 织梦官方在2015年6月18日更新了织梦5.7,为了兼容php5.4+,修改了/ ...

  10. 用CSS实现“表格布局”

    当我们进行浮动布局时,会发现存在着非浮动元素与浮动元素的底部难以对齐的情况,这就是浮动布局的缺陷.因此,过去的前端工作者曾利用<table>以实现"表格布局".因为表格 ...