2017 Multi-University Training Contest 1 && HDOJ 6035 Colorful Tree 【搜索】


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≤cin)

Each of the next
n−1 lines contains two positive integersx,y (1≤x,yn,xy), 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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值