HDU 4705 立方和拆解

HDU 4705 立方和拆解

题意

给一棵树,找出所有的(A,B,C)三元组的数量,满足ABC不能同时被一条路径覆盖

思路

  • 首先可以明确的是,对于每个入度大于等于3的点(也就是有两个或以上儿子的节点),对答案都有贡献,并且这个贡献是任意三个与其相连的部分的权值乘积的加和。(由于每个节点的“分叉位置”不用,所以不会出现重复记录的现象)

  • 也就是说,从根节点(我们取1节点为根)开始,进行到一棵以某节点为根的子树时,设这棵子树权值为 \(q_0\), 而此节点下面的子树权值为 \(q_1, q_2 ··· q_s\), 我们要算的就是

\[\sum_{i = 0}^{s - 2}{\sum_{j = i + 1}^{s - 1}{\sum_{k = j + 1}^{s}{q_i * q_j * q_k}}} \]

  • 但是我们肯定不能n^3来算,这个时候可以模仿序列和的平方化任意两数乘积加和的公式:

\[((\sum_{i = 0}^{s}{q_i})^2 - \sum_{i = 0}^{s}{q_i ^ 2}) / 2 = \sum_{i = 0}^{s - 1}{\sum_{j = i + 1}^{s}{q_i * q_j}} \]

来写出序列和的立方化任意三数乘积加和的公式:

\[((\sum_{i = 0}^{s}{q_i})^3 - 3 * \sum_{i = 0}^{s}{q_i ^ 2} *\sum_{i = 0}^{s}{q_i} + 2 * \sum_{i = 0}^{s}{q_i ^ 3}) / 6 = \sum_{i = 0}^{s - 2}{\sum_{j = i + 1}^{s - 1}{\sum_{k = j + 1}^{s}{q_i * q_j * q_k}}} \]

这样就可以O(n)搜索算出答案了

AC代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

int n;
int vv[200005], nex[200005], fir[100005];
long long sz[100005];
long long ans = 0;

void dfs1(int o, int fa)
{
	sz[o] = 1;
	for (int i = fir[o]; i; i = nex[i])
	{
		if (vv[i] != fa)
		{
			dfs1(vv[i], o);
			sz[o] += sz[vv[i]];
		}
	}
}

void dfs(int o, int fa)
{
	long long ext = n - sz[o];
	long long c3 = ext * ext * ext;
	long long c2 = ext * ext;
	long long c1 = ext;
	int cnt = 0;
	for (int i = fir[o]; i; i = nex[i])
	{
		if (vv[i] != fa)
		{
			++cnt;
			c3 += sz[vv[i]] * sz[vv[i]] * sz[vv[i]];
			c2 += sz[vv[i]] * sz[vv[i]];
			c1 += sz[vv[i]];
			dfs(vv[i], o);
		}
	}
	if (cnt >= 2)
	{
		ans += (c1 * c1 * c1 - 3 * c2 * c1 + 2 * c3) / 6;
	}
}

int main()
{
	while (scanf("%d", &n) == 1)
	{
		memset(nex, 0, sizeof(int) * (2 * n + 2));
		memset(fir, 0, sizeof(int) * (n + 2));
		memset(sz, 0, sizeof(long long) * (n + 2));
		ans = 0;
		for (int i = 1; i < n; ++i)
		{
			int u;
			scanf("%d%d", &u, &vv[i]);
			vv[i + n] = u;
			nex[i] = fir[u];
			fir[u] = i;
			nex[i + n] = fir[vv[i]];
			fir[vv[i]] = i + n;
		}
		dfs1(1, 0);
		dfs(1, 0);
		printf("%lld\n", ans);
	}
	return 0;
}
posted @ 2020-12-08 21:16  _int_me  阅读(99)  评论(0编辑  收藏  举报