• 【图论】CF1467E


    题目链接: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个月前强大了,无论是从代码能力、逻辑分析能力、或者是恒心和耐心都是。

  • 相关阅读:
    牛客-编程题
    Python 实现一键发布项目
    IDEA MyBatis Log Plugin 收费了,这个可以替代用
    微信 for Windows 内测3.3.0版本,能刷朋友圈啦!
    实况摄像头,“偷窥” 世界美景!
    阿里云盘PC/MAC客户端内测版
    我十年前的工位 vs 我现在的工位
    设置电脑屏保全屏显示时间,酷!
    自我介绍
    Bartender 处理日期格式化
  • 原文地址:https://www.cnblogs.com/purinliang/p/14257293.html
Copyright © 2020-2023  润新知