树的点分治(HDU 5977 && 2016ICPC大连 G: Garden of Eden)

树的点分治(HDU 5977 && 2016ICPC大连 G: Garden of Eden)_第1张图片


题意:

有一棵n个节点的数,每个点都有一个值(1<=pi<=k),问有多少条路径满足包含1到k中的所有数字


可以想到状压+树形dp,但是开dp[50005][1025]的数组内存占用过大,复杂度也高,所以无法实现

那就只能树分治了


树的重心:如果一个点,满足其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心

删去重心后,生成的多棵树尽可能平衡

树的点分治过程:

①找到当前树的重心,把这个重心当成树的根

②计算经过该点的路径个数

③删掉这个重心,删除之后对形成的多棵树每一棵再次进行步骤①直到所有点都遍历过一遍


复杂度:

一定会找n次重心,每次对子树找重心时,子树的平均大小不会超过logn,所以总体复杂度为O(nlogn),常数>=3

代码里有解析,具体看代码(这居然是银奖题。。这么难)

#include
#include
#include
#include
using namespace std;
#define LL long long
vector G[50005];
int bet, heart, k, sum, val[50005], vis[50005], size[50005], rec[50005];
LL ans, cnt[1024];
void Sech1(int u, int p)
{
	int i, v;
	size[u] = 1;
	for(i=0;i

你可能感兴趣的:(#,分治与分块)