zoukankan      html  css  js  c++  java
  • DFS序

    转自:https://blog.csdn.net/qq_36368339/article/details/79236467

    树通常有多种类型,但其终归是非线性结构,操作起来有时总是那么费时。

    例如:POJ 3321
    给你一棵树,树上每个节点都有1个苹果,然后你对一个节点操作,如果有苹果就拿走,没苹果就放上,然后询问你以x为根的子树上共有多少个苹果。
    每次更新都要遍历一遍,查询也要遍历一遍,时间复杂度很高。如果能转化成线性结构就可以了,就可以用线段树或者树状数组等其他方法对树高效更新和查询。
    dfs有一个很好的性质:一棵子树所在的位置处于一个连续区间中。
    DFS序就是将树形结构转化为线性结构,用dfs遍历一遍这棵树,进入到x节点有一个in时间戳,递归退出时有一个out
    时间戳,x节点的两个时间戳之间遍历到的点,就是根为x的子树的所有节点,他们的dfs进入时间戳是递增的。同时两个时间戳构成了一个区间,x节点在这段区间的最左端,这个区间就是一棵根节点为x的子树,对于区间的操作就是其他维护方式的应用了。

     1 int time = 0;
     2 inline void dfs(int x, int fa) {
     3     in[x] = ++time; //进入的时间戳
     4     num[time] = x;  //生成新的线性结构
     5     for(int i = 0; i < G[x].size(); i++) {
     6         int cnt = G[x][i];
     7         if(cnt == fa) continue;
     8         dfs(cnt, x);
     9     }
    10     out[x] = time;  //出去的时间戳
    11 }

    in[x]表示映射的DFS预处理出的线性结构,也就是说x是原始节点,in[x]是x节点的新位置,num[t]表示第t个节点的编号,num[in[x]]表示的还是x。num是新序列,in表示是新序列的下标,in[x]~out[x]是x为根结点的子树,划分为一个区间。
    ps:可以在纸上模拟画画.

    回到最初问题:
    单点更新,区间查询,将这个树的DFS序预处理出来,线段树维护区间和。用num[L]建树(建树时小心,产生了新序列),in[x]单点更新,in[x]~out[x]区间查询,问题即可解决。

  • 相关阅读:
    重回大一
    20071027我以为我很大度
    凌晨三点
    山洞爱情
    JQuery上传插件Uploadify使用详解
    jquery ui layout
    win2003下direct的问题
    Aptana一些快键用法
    IE、Firefox、Chrome 的JS代码兼容注意事项
    2011学习计划
  • 原文地址:https://www.cnblogs.com/wsy107316/p/11958059.html
Copyright © 2011-2022 走看看