题目大意
有n+1棵树,第一棵为一个点,编号0
从i=1~n读入a,b,c,d,l表示用权值为l的边连接Tree a的点c和Tree b的点d,对每一棵树,输出树里面的点两两之间的距离
即ans[i]=,d为点i,j的距离
数据范围:
对于30% 的数据,m <= 8
对于60% 的数据,m <= 16
对于100% 的数据,1 <= m<= 60,T<= 100
分析
不难发现ans_i由几个部分相加得来:
1、ans[Tree a]+ans[Tree b];
2、size[Tree a]*size[Tree b]*l(在求距离的过程中,新边一共被累加了size[Tree a]*size[Tree b]次,因为对于所有i属于Tree a,j属于Tree b,i,j之间的路径上一定有新边l);
3、Tree a中所有点到c点的距离*size[b]+Tree b中所有点到d点的距离*size[a];
而对于前两种情况,都可以用记录下来,在需要用到的时候直接累加;
第三种情况中,以Tree a为例:
若c在a的第一棵子树上,则所求的值就是第二棵子树上所有点到c的距离和+第一棵子树上所有点到c的距离和;
于是前者可以转化成第二棵子树上左右点到d(这个d是连接这棵树时的关键点,不是d_i)的距离+l(连接这棵树时的新边)+c_i到c(这个c是连接这棵树时的关键点,不是c_i);前者和后者都可以递归实现。
代码略O(∩_∩)O~~
PS:由于搜索量较大,需要用到记忆化搜索。C++选手可以用map容器,Pascal选手就要打hash了。