「HLOI2015」Tree

题目描述

Chavo 有一颗水晶树,树上会结出魔法水晶。包括树根在内,树一共有 个分叉的节点,其中 号节点为树根,初始状态下每一个节点都有一个生长值 。Chavo 有一根法杖,法杖可以对某个节点 释放生长法术,使得以 为根的子树的每个节点的生长值更新为 。对于每一个被更新的节点来说, 的定义都不一样,其中 是在释放法术之前被更新节点的生长值, 是在释放法术之前节点 的生长值。但是对于所有被更新的节点来说, 的递推公式都一样,是 。

Chavo 想要释放 次生长法术,每次法术都给定 ,她想问问你释放法术之后所有节点的生长值的和是多少?结果要对 取模后输出。

输入

第一行输入整数 和 ;

第二行输入 个整数,第 个整数代表第 个节点上初始值 ;

接下来 行,每一行有两个正整数 ,代表树上第 个节点和第 个节点有树杈相连;

接下来 行,每一行有 个正整数 ,如题目描述。

输出

输出一个整数代表经过所有操作后整棵树上所有节点数的和,结果要对 取模后输出。

样例输入

1
2
3
4
5
6
3 2
3 4 5
1 2
1 3
1 2 2
2 3 3

样例输出

1
19

样例说明

第一次操作时,更新 号点,对于 号点, ,更新后 号点值为 ,同理 号点值为 。

第二次操作时,更新 号点, ,更新后 号点为 。

最后求和为 。

数据范围及约定

对于 的数据, ;

对于 的数据, ;

对于 的数据, 。

时间限制与空间限制

时间限制:,空间限制:。

题解

推式子

注意, 是对于子树内每个点说的……每个点的 不一定相同,不过都是该点的权值。

树上实现子树修改和查询,搞出来个 DFS 序就变成了区间问题,线段树即可解决。

但是这什么鬼畜修改。这个类似于斐波那契数列的递推关系。 先看看 的一些值有什么规律:

如果我们定义一个类斐波那契数列 , , , 就可以这样描述了:

那么就可以想到如下两种算法。

算法一

注意到修改可以分为两部分,是给这个点的子树内所有节点的权值先乘上 ,再加上 。于是先做一个区间乘法,然后利用矩阵算出要加的部分,最后做一个区间加法即可。

时间复杂度为 ,空间复杂度为 。

算法二

算法一中,需要区间乘,区间加,区间覆盖,虽然很快但不好敲代码(好吧我承认其实也挺好写的……),所以考虑用一个矩阵乘法完成所有操作。

线段树中叶子节点维护的矩阵 这样构造:

其中, 为此时这个节点的的权值,线段树上非叶子节点维护的都是单位矩阵,方便之后下传矩阵。

每次修改需要乘的矩阵 是两个矩阵的乘积:

其中, 是节点 的生长值, 意义与题中相同。

那么这么乘能乘出来些什么?

为了方便,令:

发现 这个矩阵是这样的:

那么, 就是这样的:

是这样的:

更新一个节点后,矩阵就是这样的:

的位置顺利被 替代,构造成功。

那么,如何更新答案?

对于线段树矩阵,更新一个区间时 矩阵乘 ,每次查询节点 的生长值时,将这一区间矩阵下传,之后清为单位矩阵。

最后,将线段树上非叶子节点全部下传清为单位矩阵后,统计答案。即将矩阵中的 加起来。

时间复杂度为 ,空间复杂度为 。

代码见这里。