zoukankan      html  css  js  c++  java
  • 20200611题解:树网的核

    树网的核 洛谷P1099

    这是一道非常修仙的题目。算法都很不正经。袁老师告诉我这是一道DP题,一看又是树上的题目,我就以为是树形dp,但是题解里没有树形DP。

    看题解的时候我的心仿佛被放入了冰箱冷冻室的绿豆糕一样,因为我最怕的就是这种钻数据空子的不优美算法(因为这种算法的得分是看脸的)。在心态恢复后的第二天下午,我发现实际上它们只是看起来不优美;实际上,把性质分析完毕之后这道题就根本不是一道树形题目了,所以看起来才不对劲。我决定用一篇论文的题解来把这道题消化。

    树形DP

    这是我的算法:

    dp[u][l][0/1] = 以u为根节点,链的长度为l,能否往上走,在此子树中的最小偏心距。
    

    前期都很顺利。但是当我要求dp[u][l][0]的时候,发现无法求了。你不能直接拿它从dp[u][l - j][1]dp[v][j][1]转移过来,因为dp[u][l][1]的值是包括了来自v的子树到u的偏心距候选项的,而且没办法把它消掉。如果要消掉,就得再开一维k表示不考虑u的子树k提供的偏心距候选项。这样就超空间了,而且极其麻烦,不知道哪里又会埋藏着什么错误。

    而且这个算法是没有用到题目提供的一些性质的(比如这条链肯定是在直径上)。所以肯定不对。

    不过,在使用这个算法的过程中学会了求树的中心。

    暴力

    因为数据太弱,所以这个(O(N^4))暴力居然可以过。

    因为答案肯定是在直径上,所以做题者想出了一个办法。先用传统的dfs法搜出直径的其中一端,那么从这个点搜出去的所有路径肯定就会包括所有直径(因为直径有一条性质:在边权大于等于0的树上,所有直径的并集肯定是一棵树。用反证法可以证明)。然后,我们要找的路径就肯定是一条连接祖宗和孩子的路径了。枚举两个点i,j使得ji的祖先,再枚举路径上的所有点k,再从每一个点k深搜更新整棵树各个点到这条路径的最短距离,最后再扫描全图得到答案。

    树的中心

    用“求树的中心”的那一节的算法,可以“求出对于每个点i,离它最远的点离它的距离“。

    树的中心:设f(u)=离点u最远的点到点u的距离。f(u)最小的点就被称为树的中心。

    首先任意指定一个根,这样才能树形DP。

    f(u)要被分为两个部分,一个是u的子树内离u最远的(设为g(u)),一个是u的子树外离u最远的(设为h(u))。

    子树内最远的很好解决;子树外最远的怎么做呢?

    子树外最远的这个点到u的路径肯定经过u的父亲。所以,如果我们先求出了g(fa[u])和h(fa[u]),那么就可以用父亲的数据得到u的h(u)了。

    但是,如果u正好是g(fa[u])所选择的那一个子树,就会导致边 <u,fa[u]>被来回走了两次。这当然是不合法的;所以我们还需要保存g(fa[u])所选择的是哪一个子树,并求出每个点的子树内离u第二远的(设为l(u))点到u的距离。

    然后就可以F(u, 1, n) f[u] = max(g[u], h[u]);了。

    但是好像这个东西在这道题里并没有什么用。

    证明:并不需要枚举每条直径,只需要任意一条(证明摘自题解)

    那么如果一棵树有多条直径怎么办呢?没关系,任选一条即可。首先,两条直径不可能不相交。把相交的那一部分看成一个点,剩下的直径部分就会关于这个点对称。而如果选择的路径包含了分叉点,其偏心距就是恒定的(这个分叉点到直径末端的距离),所以可以任选一条直径求解。

    优化

    当我们找到了一条直径,这道题就变成了一道序列题。

    当我们选择其中的一个子段时,这个子段的答案包括两部分:子段的两端到直径的两端有两个距离k1,k2,以及每一个子段中的点往直径的两边搜索得到的答案f(u)。因为不会重复搜到点,所以求出所有的f(u)的时间是(O(N))的。k1,k2可以在dfs出整棵树的depth[]之后(O(1))求。所以,预处理出depth[]f(u)后,这就真的成了一个滑动窗口的题目了。

    单调队列可以O(N)解决。

    所以 (N le 300) 的数据范围完全可以再加大:据说BZOJ上有这道题的原题,数据范围是(5 imes10^5)

  • 相关阅读:
    智慧园区数字孪生平台GIS+三维可视化的研究
    树莓派联通家庭宽带端口映射
    NetCore 5.0 Dokcer中发布报NU3028、NU3037
    django导入导出excel实践
    MySQL JSON类型
    业务、设计模式、算法
    VIM 简单教程
    k8s go-client 使用简介
    如何健壮你的后端服务
    公共dto打包时按条件导出实现feignclient接口的bean,解决feign.Feign$Builder类找不到的问题
  • 原文地址:https://www.cnblogs.com/lightmain-blog/p/13094608.html
Copyright © 2011-2022 走看看