【图论】CF1467E - Distinctive Roots in a Tree

题目链接:https://codeforces.com/contest/1467/problem/E

观察

对于某种权值 \(val\) ,若点 \(i\) 的权值 \(a[i]=val\) 则把这个点染成黑色,其他的点染成白色。

定义黑色节点的数量,为权值 \(val\) 的出现次数 \(cnt[val]\)
若以点 \(r\) 为根节点进行先序遍历,定义从点 \(r\) 到点 \(u\) 经过的黑色节点的数量,为权值 \(val\) 的深度 \(dep[val][u]\) ,记出现的最大深度为 \(mdp[val]\)

情形A:\(cnt[val]=1\) ,说明权值 \(val\) 不影响答案。
情形B:\(cnt[val]\geq2,mdp[val]=1\) ,说明删除所有的黑色节点后,合法的答案必须和根节点 \(r\) 处在同一连通块中。
情形C:\(cnt[val]\geq2,mdp[val]=2\) ,情况非常复杂。
情形D:\(cnt[val]\geq2,mdp[val]\geq3\) ,说明权值 \(val\) 直接导致答案无解。

算法流程

  1. 以点 \(1\) 为根节点,先序遍历这棵树,记录以下信息:
    每一种权值的出现次数 \(cnt[i]\)
    每一种权值的深度 \(dep[i]\)
    每一种权值的最大深度 \(mdp[i]\)

  2. 以点 \(1\) 为根节点,再次先序遍历这棵树,记录以下信息:
    假如这种权值的出现次数 \(cnt[i]=1\) ,那么直接忽略这种权值,结束。
    假如这种权值的最大深度 \(mdp[i]=1\) ,那么给这种权值的所有点都打上 \(down\) 标记,结束。
    那么这种权值的最大深度 \(mdp[i]\geq2\),那么给这种权值的所有点都打上 \(down\) 标记,给这种权值的所有 \(dep[i]\geq2\) 的点的前一个点打上 \(dirup\) 标记,结束。

  3. 记某个点为 \(u\) ,记点 \(u\) 的父节点为点 \(p\) ,则:
    \(down[u]\) 标记 表示以点 \(1\) 为整棵树的根节点时,以点 \(u\) 为根节点的整个连通块都是非法的。
    \(dirup[u]\) 标记 表示以点 \(u\) 为整棵树的根节点时,以点 \(p\) 为根节点的整个连通块都是非法的。
    假如 \(dirup[u]=cnt[a[p]]-1\) ,则说明以点 \(u\) 为整棵树的根节点时,权值 \(a[p]\) 的分布恰好为情形B,所以要清除掉点 \(p\)\(down\) 标记。

  4. 下推所有 \(down\) 标记,上推所有的 \(dirup\) 标记,统计答案。

总结

其中,要计算“带有方向的up标记”的方向,目前没有想到更好的办法,使用的是类似倍增lca的倍增算法计算出方向。总体时间复杂度 \(O(nlogn)\)
一道对我来说非常难的“树”论问题,也通过这一题感觉到自己确实比起9个月前强大了,无论是从代码能力、逻辑分析能力、或者是恒心和耐心都是。

posted @ 2021-01-10 06:26  purinliang  阅读(96)  评论(0编辑  收藏  举报