Colorful Tree
Time Limit: 6000/3000 MS (Java/Others) Memory Limit:131072/131072 K (Java/Others)
Total Submission(s): 1295 Accepted Submission(s): 511
Problem Description
There is a tree with n nodes,each of which has a type of color represented by an integer, where the color ofnodei isci.
The path between each two different nodes is unique, of which we define thevalue as the number of different colors appearing in it.
Calculate the sum of values of all paths on the tree that has n(n−1)/2 paths in total.
Input
The input contains multiple test cases.
For each test case, the first line contains one positive integers n, indicating the number of node. (2≤n≤200000)
Next line contains n integers where thei -thinteger representsci, the color of nodei. (1≤ci≤n)
Each of the next n−1 lines contains two positive integersx,y (1≤x,y≤n,x≠y), meaning an edge between node x and nodey.
It is guaranteed that these edges form a tree.
Output
For each test case, output "Case #x:y"in one line (without quotes), wherex indicates the case number starting from 1 andy denotes the answer of corresponding case.
Sample Input
3
1 2 1
1 2
2 3
6
1 2 1 3 2 1
1 2
1 3
2 4
2 5
3 6
Sample Output
Case #1: 6
Case #2: 29
【题意】给出一棵有n个节点的树,每个节点有一种颜色,任意两个节点之间的距离为两点之间的最短路径上经过点的颜色种类数(包括端点),且所有点两两之间的距离和。
【思路】我们可以逆向考虑,先算出所有路径都经过n种颜色的距离和: n * n * (n-1)/2,那么我们需要减去的便是对于每一种颜色,不经过该颜色的路径数即可。
那么该如何计算不经过每一种颜色的路径数呢?
我们用num[i]表示以i为“根节点”,其子树的节点个数和(包括自身,且整棵树的根节点,即1,事先已经确定)。
再用sum[color[u]]表示搜索到u点时,以其为根节点的每棵子树中距离u最近且颜色相等的节点x的num[x]值的和。
容易知道,每搜索一次u的根节点v,sum[color[u]]的值会变大temp,且num[v]-temp的值即表示这些点之间的路径不经过color[u]这种颜色,这种路径的数量为temp*(temp-1)/2,应减去,重复此操作即可。
#include <cstdio>
#include <vector>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define rush() int T;scanf("%d",&T);while(T--)
typedef long long ll;
const int maxn = 200005;
const int mod = 20090717;
const int INF = 0x3f3f3f;
const double eps = 1e-9;
int n;
ll ans;
int num[maxn];
int sum[maxn];
int color[maxn];
vector<int>vec[maxn];
void dfs(int u,int from)
{
int add=0;
num[u]=1;
for(int i=0;i<vec[u].size();i++)
{
int v=vec[u][i];
if(v==from) continue;
int pre=sum[color[u]];
dfs(v,u);
num[u]+=num[v];
int temp=num[v]-(sum[color[u]]-pre);
ans-=(ll)temp*(temp-1)/2;
add+=temp;
}
sum[color[u]]+=add+1;
}
int main()
{
int cas=1;
int u,v;
while(~scanf("%d",&n))
{
mst(num,0);
mst(sum,0);
for(int i=1;i<=n;i++)
{
scanf("%d",&color[i]);
vec[i].clear();
}
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
vec[u].push_back(v);
vec[v].push_back(u);
}
ans=(ll)n*n*(n-1)/2;
dfs(1,-1);
for(int i=1;i<=n;i++)
{
int temp=n-sum[i];
ans-=(ll)temp*(temp-1)/2;
}
printf("Case #%d: %I64d\n",cas++,ans);
}
return 0;
}