HDU 6035 Colorful Tree dfs

题目



Colorful Tree

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 2106    Accepted Submission(s): 897


Problem Description
There is a tree with  n  nodes, each of which has a type of color represented by an integer, where the color of node  i  is  ci .

The path between each two different nodes is unique, of which we define the value as the number of different colors appearing in it.

Calculate the sum of values of all paths on the tree that has  n(n1)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.  (2n200000)

Next line contains  n  integers where the  i -th integer represents  ci , the color of node  i (1cin)

Each of the next  n1  lines contains two positive integers  x,y   (1x,yn,xy) , meaning an edge between node  x  and node  y .

It is guaranteed that these edges form a tree.
 

Output
For each test case, output " Case # x y " in one line (without quotes), where  x  indicates the case number starting from  1  and  y  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

题目大意


  给你一个数组,每一个点代表一种颜色,然后给你几条相邻路径,求每种颜色经过的路径的和,注意两个点以上叫路径,单个点不是路径


解题思路


反向思路,用总路径数减去每种颜色不可能经过的路径,所以只需要找出每一种颜色在图中不可能经过的联通块的大小就可以,这里用的dfs,具体看代码吧,感觉讲不明白,给师弟讲了半天自己感觉很受伤

先贴上一种很好想的思路

#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
#define read(a) scanf("%d",&a)
#define Set(a,b) memset(a,b,sizeof(a))
const int mod=1e9+7;
const int maxn=200000+10;
int n;
LL ans;
int c[maxn],sum[maxn],siz[maxn];// sum数组存遍历到当前位置以本颜色为根的子树的和
bool vis[maxn];
int case_=1;
vector<int>e[maxn];
LL path(LL a)
{
    return a*(a-1)/2;
}
void dfs(int x,int fa)
{
    siz[x]=1;
    int addsum=0;//遍历完所有子树,本颜色的子树增加的大小
    for(auto &y:e[x])
    {
        if(y==fa)
            continue;
        int oldsum=sum[c[x]];
        dfs(y,x);
        int add=sum[c[x]]-oldsum; //增加的子树的大小
        ans=ans+path((LL)siz[y]-(LL)add);
        addsum+=add;
        siz[x]+=siz[y];
    }
    sum[c[x]]+=siz[x]-addsum;
}
void work()
{
    ans=0;
    Set(c,0);
    Set(sum,0);
    Set(siz,0);
    Set(vis,0);
    int tot=0;
    for(int i=1;i<=n;i++)
    {
        e[i].clear();
        read(c[i]);
        sum[c[i]]++;
        if(sum[c[i]]==1)
            tot++;
    }
    Set(sum,0);
    int u,v;
    for(int i=1;i<n;i++)
    {
        read(u);read(v);
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs(1,-1);
    vis[c[1]]=1;
    for(int i=2;i<=n;i++)
    {
        if(!vis[c[i]])
        {
            ans+=path(n-sum[c[i]]);
            vis[c[i]]=1;
        }
    }
    LL myans=tot*path((LL)n)-ans;
    printf("Case #%d: %lld\n",case_++,myans);
}
int main()
{
   // freopen("1003.in", "r", stdin);
   // freopen("data.out", "w", stdout);
    while(~read(n))
    {
        work();
    }
    return 0;
}


这下面贴上标程,也是自己写的,可能和标程有点出入,不过思想来自标程

#include<cstdio>//c++ 11标准进行编译 auto move 不清楚请自行百度
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
#define read(a) scanf("%d",&a)
const int maxn=200000+10;
int L[maxn],R[maxn],n,siz[maxn],f[maxn];//L存的是第几个进入dfs,R存的是子树中(包括自己)在哪一个dfs出来的
vector<int> e[maxn],c[maxn];
int case_=1;
void dfs(int x,int fa, int && ncnt)
{
    siz[x]=1; f[x]=fa;
    L[x]=++ncnt;
    for(auto y:e[x])
    {
        if(y==fa)
            continue;
        dfs(y,x,move(ncnt));
        siz[x]+=siz[y];
    }
    R[x]=ncnt;
}
bool cmp(int x,int y)
{
    return L[x]<L[y];
}
void work()
{
    memset(L,0,sizeof(L));
    memset(R,0,sizeof(R));
    memset(siz,0,sizeof(siz));
    for(int i=0;i<maxn;i++)
    {
        e[i].clear();
        c[i].clear();
    }
    int x;
    for(int i=1;i<=n;i++)
    {
        read(x);
        c[x].push_back(i);
    }
    int u,v;
    for(int i=1;i<n;i++)
    {
        read(u);read(v);
        e[u].push_back(v);
        e[v].push_back(u);
    }
    e[0].push_back(1);//建立虚根,不需要处理特殊情况
    dfs(0,0,0);
    LL res = (LL)n * n * (n - 1) / 2;
    for(int i=1;i<=n;i++)
    {
        if(c[i].empty())
        {
            res -= (LL) n * (n - 1) / 2;
            continue;
        }
        c[i].push_back(0);
        sort(c[i].begin(),c[i].end(),cmp);
        for(auto &x:c[i])
        {
            for(auto &y:e[x])
            {
                if(y==f[x])
                    continue;
                int si=siz[y];
                int k=L[y];
                while(1)
                {
                    L[n+1]=k;
                    auto it=lower_bound(c[i].begin(),c[i].end(),n+1,cmp);//返回根据cmp排序的一个大于等于"n+1"的数
                    if(it==c[i].end()||L[*it]>R[y])
                        break;
                    si-=siz[*it];
                    k=R[*it]+1;
                }
                res-=(LL)si*(LL)(si-1)/2;
            }
        }
    }
    printf("Case #%d: %lld\n" , case_++ , res);
}
int main()
{
    // freopen("1003.in", "r", stdin);
     //freopen("data.out", "w", stdout);
     while(~read(n))
     {
         work();
     }
     return 0;
}



Colorful Tree

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 2106    Accepted Submission(s): 897


Problem Description
There is a tree with  n  nodes, each of which has a type of color represented by an integer, where the color of node  i  is  ci .

The path between each two different nodes is unique, of which we define the value as the number of different colors appearing in it.

Calculate the sum of values of all paths on the tree that has  n(n1)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.  (2n200000)

Next line contains  n  integers where the  i -th integer represents  ci , the color of node  i (1cin)

Each of the next  n1  lines contains two positive integers  x,y   (1x,yn,xy) , meaning an edge between node  x  and node  y .

It is guaranteed that these edges form a tree.
 

Output
For each test case, output " Case # x y " in one line (without quotes), where  x  indicates the case number starting from  1  and  y  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
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值