树和图的遍历是一种典型的序关系。在某些情况下,可以利用这种序关系简化问题。
原题:一棵含有n个结点的树,所有的结点依次编号为1,2,3,……,n,每个结点v有一个权值s(v),也分别是1,2,3,……,n。对于编号为v的结点,定义t(v)为v后代中所有权值小于s(v)的结点个数。现给出这棵树及t(1), t(2), t(3),……,t(n),求出这棵树每个结点的权值(多组解只需输出一组)。
这道题看起来似乎跟这道树的统计 有点类似,但是仔细想想,其实是不太一样的。树的统计那道题,主要是要有目标意识,从树的DFS和逆DFS的性质结合图形挖掘出目标函数,从而各个击破,求出最后的解。
而这道题,我们稍微想一下就能发现,绝对是有多组解的(比如同一个结点的两个子节点都为叶子结点,则这两个叶子结点可以互换权值),那这就暗示我们要用构造法,构造出一个满足的解出来!
t(v)的定义暗示我们利用DFS来处理这个问题,因为先序遍历的一个重要特性就是每个结点的后代都紧跟在其后面被遍历。因此我们可以构造一个这样的权值集合:根据树的DFS序列,在插入一个节点v时,每次在其前面保留恰好连续t[v]个空位置。按照这种方式构造出来的解,能够满足题目要求。
树的DFS序列为: 1 2 4 5 7 3 6 8 9
对应的t值分别为: 3 1 0 0 0 3 1 0 0
原始状态:
1.插入节点1,t[1]=3,故将其插在第4个位置
2.插入节点2,t[2]=1,故插入在第2个位置
3.依次插入4,5,7得到:
4.这时要插入3,应在其前面留下连续3各空档,故插在最后一个空位
5.按照此法依次插入剩下的节点,得到权值序列:
将index和节点序号依次对应
即可得到各个节点对应的权值:
1:4, 2:2, 3:9 , 4:1, 5:3, 6:7, 7:5, 8:6, 9:8
这里我们也可以看到:节点8和9的权值是可以互换、4、5、7的权值也是可以自由组合的,因此也验证了此题的解的不唯一性。
如何实现将一个节点插入恰好连续t[v]个空格之后呢?将《树的统计》一题中的线段树稍加变形,维护一个区间最大的连续空格以及,区间左、右最大的连续空格数,每次插入或删除节点的时候,对区间的各个最大值进行更新即可。
c++代码如下:
输入:
输出: