dfs序
今天下午不想做题,蹭了一区教练一节课,这跟我想象的区别有点大啊,我只能说我就是个废物。。。
不说了,自己的思维还是很不到位,自己再捋一捋。
\(dfs\) 序
简介
概念
\(dfs\) 序就是将树上的节点按照先根遍历的顺序进行遍历的到的节点顺序。
性质
一棵子树的所有节点处在一个连续的区间内。
用处
可以将一些序列问题转化为树上问题,套树状数组和线段树使用。
这不是我们的重点,简单一提就过去了。
\(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\) 即可。
总结
-
看到链,想 \(u-root\),\(v-root\),\(LCA(u,v)-root\),\(fa(LCA(u,v))-root\)。
-
看到子树,想区间
-
思考问题时考虑哪些点对于询问有贡献。