[BestCoder Round #88]Tree Cutting

来源:互联网 发布:python数组长度 编辑:程序博客网 时间:2024/04/29 07:32

题目大意

给定一棵n个节点的树,每个点有权值vi。‘
定义一棵树的权值为所有点权异或和。
现在对于[0,m)的所有整数k,请统计出这棵树有多少个联通子树的权值为k
联通子树:树的一个联通子图(显然它也是一棵树)
一个测试点T组数据。

1T10,1n103,1m210,vi[0,m)
保证m2的非负整数幂。


题目分析

Solution 1

考虑如果我们确定某个点是一定要选取的,那么我们将其作为根。
那么树中一个点如果选了,它的父亲一定要被选取。
这个树形依赖关系是不是特别熟悉?对了,就是和[JSOI2016]最佳团队类似的模型。
按照DFSdp,使用fi,j表示i一定要选,异或和为j的方案数。那么可以分两种选和不选两种情况考虑转移,和上面说的那题是一样的,很简单就不细讲了。
但是一次dpO(nm)的,难道我们要做n次?而且这样还会有重点。
可以发现一个点如果考虑过,那么就可以将问题分配到它的几个子树来分治了。这个就是经典的点分治,每次选取重心dp即可。
时间复杂度O(nmlog2n)
很不错的一个思想。

Solution 2

1作为树根,然后每个联通子树肯定有且仅有一个最高点。
fx,i表示x设为最高点,异或和为i的方案数。可以列出dp方程:

fx,i+=jkfx,jfy,k

这是标准的异或卷积形式,可以使用FWTmlog2m时间内计算出来。
我们会计算O(n)次(边数)FWT,总时间复杂度O(nmlog2m)
这个方法比较显然,但是像我这样的不会FWT的人在比赛时虽然是想出来了也无能为力。

0 0