• DFS序详解


    dfs序就是一棵树在dfs遍历时组成的节点序列.

    它有这样一个特点:一棵子树的dfs序是一个区间.
    下面是dfs序的基本代码:
    void dfs(int x,int pre,int d){//L,R表示一个子树的范围  
        L[x]=++tot;  
        dep[x]=d;  
        for(int i=0;i<e[x].size();i++){  
            int y=e[x][i];  
            if(y==pre)continue;  
            dfs(y,x,d+1);  
        }  
        R[x]=tot;  
    }  

     

    给定一颗树, 和每个节点的权值.下面有7个经典的关于dfs序的问题:

    1. 对某个节点X权值加上一个数W, 查询某个子树X里所有点权的和.

    由于X的子树在DFS序中是连续的一段, 只需要维护一个dfs序列,用树状数组实现:单点修改和区间查询.

    2. 对节点X到Y的最短路上所有点权都加一个数W, 查询某个点的权值.
    这个操作等价于a. 对X到根节点路径上所有点权加W
    b. 对Y到根节点路径上所有点权加W
    c. 对LCA(x, y)到根节点路径上所有点权值减W
    d. 对LCA(x,y)的父节点 fa(LCA(x, y))到根节点路径上所有权值减W

    于是要进行四次这样从一个点到根节点的区间修改.将问题进一步简化, 进行一个点X到根节点的区间修改, 查询其他一点Y时,只有X在Y的子树内, X对Y的值才有贡献且贡献值为W.当单点更新X时,X实现了对X到根的路径上所有点贡献了W.于是只需要更新四个点(单点更新) ,查询一个点的子树内所有点权的和(区间求和)即可.

    3. 对节点X到Y的最短路上所有点权都加一个数W, 查询某个点子树的权值之和.
    同问题2中的修改方法, 转化为修改某点到根节点的权值加/减W
    当修改某个节点A, 查询另一节点B时
    只有A在B的子树内, Y的值会增加
    W * (dep[A] - dep[B] + 1) => W * (dep [A] + 1) - W * dep[B]
    那么我们处理两个数组就可以实现:
    处理出数组Sum1,每次更新W*(dep[A]+1),和数组Sum2,每次更新W.
    每次查询结果为Sum1(R[B]) – Sum1(L[B]-1) - (Sum2(R[B]) – Sum2(L[B]-1)) * dep [B].


    4. 对某个点X权值加上一个数W, 查询X到Y路径上所有点权之和.
    求X到Y路径上所有的点权之和, 和前面X到Y路径上所有点权加一个数相似
    这个问题转化为
    X到根节点的和 + Y到根节点的和 - LCA(x, y)到根节点的和 - fa(LCA(x,y)) 到根节点的和
    更新某个点x的权值时,只会对它的子树产生影响,对x的子树的每个点到根的距离都加了W.
    那么我们用”刷漆”(差分前缀和),更新一个子树的权值.给L[x]加上W,给R[x]+1减去W,那么sum(1~L[k])就是k到根的路径点权和.

    5. 对节点X的子树所有节点加上一个值W, 查询X到Y的路径上所有点的权值和
    同问题4把路径上求和转化为四个点到根节点的和
    X到根节点的和 + Y到根节点的和 - LCA(x, y)到根节点的和 - parent(LCA(x,y)) 到根节点的
    再用刷漆只更新子树.
    修改一点A, 查询某点B到根节点时, 只有B在A的子树内, A对B才有贡献.
    贡献为W * (dep[B] - dep[A] + 1) => W * (1 - dep[A]) + W * dep[B]
    和第三题一样, 用两个sum1,sum2维护 W *(dep[A] + 1),和W.
    最后答案就是sum2*dep[B]-sum1.


    6. 对子树X里所有节点加上一个值W, 查询某个点的值.

    对DFS序来说, 子树内所有节点加W, 就是一段区间加W.
    所以这个问题就是 区间修改, 单点查询.树状数组+刷漆.


    7.对子树X里所有节点加上一个值W, 查询某个子树的权值和.
    子树所有节点加W, 就是某段区间加W, 查询某个子树的权值和, 就是查询某段区间的和
    区间修改区间求和,用线段树可以很好解决.

     
     
  • 相关阅读:
    str.format格式化用法(通过{}来替代%)
    urlparse模块(专门用来解析URL格式)
    Socket原理与编程基础
    如何查询端口号和网址的ip地址?
    urlretrieve 如何给文件下载设置下载进度?
    判断URL是否支持断点续传?
    断点续传
    HTTP协议详解之User Agent篇
    HTTP协议详解之基本认证篇
    HTTP协议详解之请求篇
  • 原文地址:https://www.cnblogs.com/bytebull/p/5929137.html
Copyright © 2020-2023  润新知