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[y]\)^\(a[lca]\),\(dis[x]\) 为点 \(x\) 到根的路径的异或和
那么普通的启发式合并做法就是开一个 \(vector\) 和 \(map\),分别记录每一状态下的最长链
然后从小到大合并所有的子树即可

考虑 \(dsu\,on\,tree\) 做法:
先按树链剖分的做法划分轻重链
然后大致思路就是:对于每一个轻儿子我们暴力合并,重儿子保留信息
为了节省空间,我们不能对每一个节点都开数组,所以开一个全局数组来维护这个东西
既然开的是全局变量,就要避免对其他子树的影响,当然就有清空操作,对于轻儿子我们暴力遍历其子树把信息删除
而一棵子树内只有一个重链,所以重链之间没有影响,可以不删除,直接保留信息
然后暴力把轻儿子子树内的信息合并,并更新答案就可以了

这样做复杂度是 \(O(n*logn)\) 的,因为一个点到根路径上的轻边只有 \(log\) 条,所以均摊复杂度是 \(O(n*log)\) 的

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int n,head[N],nxt[N],num=0,to[N],c[N],sz[N],son[N];
inline void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
int ans[N],dep[N],f[1<<22],o;
inline void dfs(int x){
    sz[x]=1;
    for(int i=head[x];i;i=nxt[i]){
        int u=to[i];
        dep[u]=dep[x]+1;c[u]^=c[x];dfs(u);sz[x]+=sz[u];
        if(sz[u]>sz[son[x]])son[x]=u;
    }
}
inline void Delet(int x){
    f[c[x]]=-N;
    for(int i=head[x];i;i=nxt[i])Delet(to[i]);
}
inline void Modify(int x){
    ans[o]=max(ans[o],f[c[x]]+dep[x]);
    for(int i=0;i<22;i++)ans[o]=max(ans[o],f[c[x]^(1<<i)]+dep[x]);
    for(int i=head[x];i;i=nxt[i])Modify(to[i]);
}
inline void ins(int x){
    f[c[x]]=max(f[c[x]],dep[x]);
    for(int i=head[x];i;i=nxt[i])ins(to[i]);
}
inline void dfs1(int x){
    for(int i=head[x];i;i=nxt[i])
        if(to[i]!=son[x])dfs1(to[i]),Delet(to[i]);
    if(son[x])dfs1(son[x]);o=x;
    for(int i=head[x];i;i=nxt[i])
        if(to[i]!=son[x])Modify(to[i]),ins(to[i]);
    f[c[x]]=max(f[c[x]],dep[x]);
    ans[o]=max(ans[o],f[c[x]]+dep[x]);
    for(int i=0;i<22;i++)ans[o]=max(ans[o],f[c[x]^(1<<i)]+dep[x]);
    ans[o]-=dep[x]<<1;
    for(int i=head[x];i;i=nxt[i])ans[x]=max(ans[x],ans[to[i]]);
}
int main(){
  freopen("pp.in","r",stdin);
  freopen("pp.out","w",stdout);
  scanf("%d",&n);
  char ch[2];int x;
  for(int i=(1<<22)-1;i>=0;i--)f[i]=-N;
  for(int i=2;i<=n;i++){
      scanf("%d%s",&x,ch);
      link(x,i);
      c[i]=1<<(ch[0]-'a');
  }
  dfs(1);dfs1(1);
  for(int i=1;i<=n;i++)printf("%d ",ans[i]);
  return 0;
}

原文地址:https://www.cnblogs.com/Yuzao/p/8660345.html

时间: 2024-08-29 19:26:58

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(dsu on tree 思路)

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

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

[2016-04-04][codeforces][639][B][Bear and Forgotten Tree 3]

时间:2016-04-04 13:11:25 星期一 题目编号:[2016-04-04][codeforces][639][B][Bear and Forgotten Tree 3] 题目大意:一棵树有n个节点,直径为d,直径为h,问,这样的树是否存在,是则输出任意一棵树的所有边 分析: 树的高度是h,那么树的直径最大为2h 所以d?2×hd?2×h 所以只需要生成第一个枝条深度为h,其他枝条深度为d-h的树即可 如果d>2×hd>2×h,那么这样的树就不存在 d == h,剩下的节点不能放在

Codeforces 741B Arpa&#39;s weak amphitheater and Mehrdad&#39;s valuable Hoses

[题目链接] http://codeforces.com/problemset/problem/741/B [题目大意] 给出一张图,所有连通块构成分组,每个点有价值和代价, 要么选择整个连通块,要么只能在连通块中选择一个,或者不选,为最大价值 [题解] 首先我们用并查集求出连通块,然后对连通块进行分组背包即可. [代码] #include <cstdio> #include <vector> #include <algorithm> #include <cstr

codeforces 742D Arpa&#39;s weak amphitheater and Mehrdad&#39;s valuable Hoses ——(01背包变形)

题意:给你若干个集合,每个集合内的物品要么选任意一个,要么所有都选,求最后在背包能容纳的范围下最大的价值. 分析:对于每个并查集,从上到下滚动维护即可,其实就是一个01背包= =. 代码如下: 1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #include <vector> 5 using namespace std; 6 const int N = 1000 + 5;

codeforces 851D Arpa and a list of numbers

目录 codeforces 851D Arpa and a list of numbers 题意 题解 Code codeforces 851D Arpa and a list of numbers 题目传送门 题意 给出\(n\)个数,有两种操作: 1.将一个数从数列中删除,代价为\(x\). 2.将一个数加1,代价为\(y\). 询问最少花费多少的代价能够使数列中所有数的\(Gcd\)不为1. \((1 \leq n \leq 5 \cdot 10^5 , 1 \leq x,y \leq 1

Codeforces 600E. Lomsat gelral(Dsu on tree学习)

题目链接:http://codeforces.com/problemset/problem/600/E n个点的有根树,以1为根,每个点有一种颜色.我们称一种颜色占领了一个子树当且仅当没有其他颜色在这个子树中出现得比它多.求占领每个子树的所有颜色之和. 我们都知道可以$BST$启发式合并从而完美${O(nlogn^{2})}$,这太丑陋了. 那么$Dsu~~on~~tree$是在干啥呢? 找出树中每一个节点的重儿子,统计答案的时候优先进入每一个点的所有轻儿子,之后再进入重儿子,目的是保留重儿子所

Codeforces Round #316 (Div. 2) D. Tree Requests 树 离线在线 算法

D. Tree Requests time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Roman planted a tree consisting of n vertices. Each vertex contains a lowercase English letter. Vertex 1 is the root of the