DFS序

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

例如:POJ 3321
给你一棵树,树上每个节点都有1个苹果,然后你对一个节点操作,如果有苹果就拿走,没苹果就放上,然后询问你以x为根的子树上共有多少个苹果。
每次更新都要遍历一遍,查询也要遍历一遍,时间复杂度很高。如果能转化成线性结构就可以了,就可以用线段树或者树状数组等其他方法对树高效更新和查询。

DFS序就是将树形结构转化为线性结构,用dfs遍历一遍这棵树,进入到x节点有一个in时间戳,递归退出时有一个out
时间戳,x节点的两个时间戳之间遍历到的点,就是根为x的子树的所有节点,他们的dfs进入时间戳是递增的。同时两个时间戳构成了一个区间,x节点在这段区间的最左端,这个区间就是一棵根节点为x的子树,对于区间的操作就是其他维护方式的应用了。

code:

int time = 0;
void dfs(int x, int fa) {
    in[x] = ++time; //进入的时间戳
    num[time] = x;  //生成新的线性结构
    for(int i = 0; i < G[x].size(); i++) {
        int cnt = G[x][i];
        if(cnt == fa) continue;
        dfs(cnt, x);
    }
    out[x] = time;  //出去的时间戳
}


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]区间查询,问题即可解决。

原文链接:https://blog.csdn.net/qq_36368339/article/details/79236467

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值