dfs序在算法在的运用

本文介绍了DFS序在算法分析中的基本概述和几类经典问题,包括单点修改、子树增加、树链修改等场景的处理方法,并提供了相关问题的模板和典型例题。
摘要由CSDN通过智能技术生成

dfs序在算法在的运用

1.算法分析

1.1 基本概述

Screenshot_20201021_143643.jpg

上面的图片dfs序列为{1, 2, 4, 3, 5, 6}

性质:

  • dfs的顺序不唯一,但是不影响使用。

  • 子树在dfs序上一定连续

1.2 几类经典问题

1.2.1 单点修改,求子树和

问题描述:

两个操作:

  • 1 a x,表示将结点a的权值增加 ;
  • 2 a,表示求结点a的子树上所有结点的权值之和。

处理方法:

求完dfs序后,在dfs序上建立树状数组(线段树)。1 a x就是单点修改,用树状数组(线段树)进行单点修改;对于2 a求子树和,由于子树的dfs序是连续的,因此就是进行区间查询,查询 d f n [ x ] ∼ d f n [ e d [ x ] ] dfn[x] \sim dfn[ed[x]] dfn[x]dfn[ed[x]]这段区间的和。

1.2.2 子树增加,子树查询

问题描述

  • 1 a x,表示将结点 的子树上所有结点的权值增加 ;
  • 2 a,表示求结点 a 的权值。

处理方法:

求完dfs序后,在dfs序上建立树状数组。对于子树增加,那么就是区间修改;对于结点的权值,就是单点求值。

1.2.3 子树增加,子树查询

问题描述

  • 1 a x,表示将结点 a 的子树上所有结点的权值增加 ;
  • 2 a,表示求结点 a 的子树上所有结点的权值之和。

处理方法:

求完dfs序后,在dfs序上建立树状数组。对于子树增加,那么就是区间修改;对于子树求和,那么就是区间询问。

1.2.4 树链修改,单点查询

问题描述:

  • 1 a b x,表示将「结点 a 到结点 b 的简单路径」上所有结点的权值都增加 ;
  • 2 a,表示求结点 a 的权值。

处理方法:

求完dfs序后,在dfs序上建立树状数组。对于树链修改, f [ ] f[] f[]是差分数组,那么采取树上差分操作: f [ a ] + = x , f [ b ] + = x , f [ l c a ( a , b ) ] − = x , f [ f a [ l c a ( a , b ) ] ] − = x f[a] += x, f[b] += x, f[lca(a, b)] -= x, f[fa[lca(a, b)]] -= x f[a]+=x,f[b]+=x,f[lca(a,b)]=x,f[fa[lca(a,b)]]=x, 那么转化为4个单点修改: a d d ( b 1 , d f n [ a ] , x ) , a d d ( b 1 , d f n [ b ] , x ) , a d d ( b 1 , d f n [ l c a ( a , b ) , − x ] ) , a d d ( b 1 , d f n [ f a [ l c a ( a , b ) ] ] , − x ) add(b1, dfn[a], x), add(b1, dfn[b], x), add(b1, dfn[lca(a, b), -x]), add(b1, dfn[fa[lca(a, b)]], -x) add(b1,dfn[a],x),add(b1,dfn[b],x),add(b1,dfn[lca(a,b),x]),add(b1,dfn[fa[lca(a,b)]],x);对于求节点a的权值,由于a的权值等于子树和的差分值相加(树上差分原理),但是子树的dfs序连续,那么相当于区间查询(求和)。

1.2.5 树链修改,子树和查询

问题描述:

  • 1 a b x,表示将「结点 a 到结点 b 的简单路径」上所有结点的权值都增加 ;
  • 2 a,表示求 的子树上所有结点的权值之和.

处理方法:

求完dfs序后,在dfs序上建立树状数组。对于树链修改, f [ ] f[] f[]是差分数组,那么采取树上差分操作: f [ a ] + = x , f [ b ] + = x , f [ l c a ( a , b ) ] − = x , f [ f a [ l c a ( a , b ) ] ] − = x f[a] += x, f[b] += x, f[lca(a, b)] -= x, f[fa[lca(a, b)]] -= x f[a]+=x,f[b]+=x,f[lca(a,b)]=x,f[fa[lca(a,b)]]=x。那么转化为4个单点修改: a d d ( b 1 , d f n [ a ] , x ) , a d d ( b 1 , d f n [ b ] , x ) , a d d ( b 1 , d f n [ l c a ( a , b ) , − x ] ) , a d d ( b 1 , d f n [ f a [ l c a ( a , b ) ] ] , − x ) add(b1, dfn[a], x), add(b1, dfn[b], x), add(b1, dfn[lca(a, b), -x]), add(b1, dfn[fa[lca(a, b)]], -x) add(b1,dfn[a],x),add(b1,dfn[b],x),add(b1,dfn[lca(a,b),x]),add(b1,dfn[fa[lca(a,b)]],x)

对于查询子树和,子树为a,对于子树a内的每个点x,子树和就是每个点x的贡献值相加。每个点x的贡献值为: f [ x ] ∗ ( d e e p [ x ] − d e e p [ a ] + 1 ) = f [ x ] ∗ ( d e e p [ x ] + 1 ) − f [ x ] ∗ d e e p [ a ] f[x] * (deep[x] - deep[a] + 1) = f[x] * (deep[x] + 1) - f[x] * deep[a] f[x](deep[x]deep[a]+1)=f[x](deep[x]+1)f[x]deep[a],其中 d e e p [ x ] deep[x] deep[x]表示x的深度,根节点的深度为1。按照差分思想,当前x节点加 f [ x ] f[x] f[x],那么它所以的父节点、祖父节点…都需要加上 f [ x ] f[x] f[x],因此对于子树和来说,需要加上 d e e p [ x ] − d e e p [ a ] + 1 deep[x] - deep[a] + 1 deep[x]deep[a]+1 f [ x ] f[x] f[x]

按照上述分析,需要维护两个数组数组,一个维护 ∑ x = l x = r f [ x ] ∗ ( d e e p [ x ] + 1 ) \sum_{x=l}^{x=r}f[x] * (deep[x] + 1) x=lx=rf[x](deep[x]+

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值