dfs序

今天下午不想做题,蹭了一区教练一节课,这跟我想象的区别有点大啊,我只能说我就是个废物。。。

不说了,自己的思维还是很不到位,自己再捋一捋。

\(dfs\)

简介

概念

\(dfs\) 序就是将树上的节点按照先根遍历的顺序进行遍历的到的节点顺序。

性质

一棵子树的所有节点处在一个连续的区间内。

用处

可以将一些序列问题转化为树上问题,套树状数组和线段树使用。

HDU3887 Counting Offspring

POJ3321 Apple Tree

CF620E New Year Tree

这不是我们的重点,简单一提就过去了。

\(dfs\) 序的 \(7\) 种模型

点修改,树查询

很明显的单点修改,区间查询,直接树状数组即可。

链修改,点查询

考虑哪些链的修改对当前点有贡献。

可以想到,只有经过这个点的链才会对这个点有贡献。

什么链会经过这条点???

有点在这个点子树内对吧。

所以我们的点查询就转化为了子树查询,也就是单点查询。

至于链修改,我们采用树上差分的思想,分别对于四个点进行修改。

所以问题转化为区间查询,单点修改,套树状数组即可。

链修改,子树和查询

修改操作相对于上面是没有改变的,改变的只是查询。

而且,查询操作也不再是简单的区间和,这里 \(v\) 的意义已经改变。

我们考虑修改操作对于查询结果的贡献。

我们可以看一个图。

我们发现,如果修改 \(1-6\) 这条链的话,对于以 \(2\) 为根的子树有贡献的点有 \(2\) 个,也就是说有深度差个点对于子树产生了贡献。

设我们修改的点为 \(x\) ,查询的子树和节点为 \(y\) ,修改的权值为 \(v\),我们的贡献值为 \((deep[x]-deep[y]+1) \times v\)

展开可以得到 \(deep[x] \times v+v-v \times deep[x]\),也就是说,我们要求的是 \(\sum deep[x] \times v+v-v \times deep[y]\)

\(deep[x]\) 可以直接一遍预处理,也就是说,我们要维护的是 \(\sum v\)\(\sum v-v \times deep[y]\)

两个树状数组维护即可。

点修改,链和查询

链和查询分成四部分来处理,问题转化为如何求某一点到根节点的和。

从贡献的角度考虑,我们发现,只有修改的点 \(y\)\(x\) 的祖先才能对 \(x\) 到根节点的和产生影响。

换句话说,修改点 \(y\) 只对它的子孙到根节点的和产生影响。

题目转化为区间修改,区间查询,区间修改用树状数组+差分维护,查询用树状数组维护。

子树修改,点查询

很明显的区间修改,点查询,树状数组差分即可。

子树修改,子树查询

很明显的区间修改,区间查询,树状数组和线段树都可。

子树修改,链和查询

子树修改肯定是区间修改,考虑如何查询。

我们还是从贡献的角度出发分析问题。

链的查询,我们还是先把链分成四段,题目转化为查询一个点到根节点的权值和。

这和我们的链修改子树和查询有些类似,都涉及到了深度。

还是来看一张图。

当我们修改的子树的根节点 \(y\)\(x\) 的祖先时,那么修改对 \(x\) 到根节点的权值和有贡献。

贡献为 \((deep[y]-deep[x]+1) \times v\),我们把式子展开,得到 \(deep[y] \times v+v-v \times deep[x]\)。两个树状数组维护 \(\sum v \times deep[x]\)\(\sum v\) 即可。

总结

  1. 看到链,想 \(u-root\)\(v-root\)\(LCA(u,v)-root\)\(fa(LCA(u,v))-root\)

  2. 看到子树,想区间

  3. 思考问题时考虑哪些点对于询问有贡献。

posted @ 2022-11-11 21:51  respect_lowsmile  阅读(10)  评论(0编辑  收藏  举报