HDU 6035 Colorful Tree dfs

来源:互联网 发布:淘宝联如何设置推广位 编辑:程序博客网 时间:2024/06/08 18:52

题目



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 #xy" in one line (without quotes), where x indicates the case number starting from 1 and y denotes the answer of corresponding case.
 

Sample Input
31 2 11 22 361 2 1 3 2 11 21 32 42 53 6
 

Sample Output
Case #1: 6Case #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 #xy" in one line (without quotes), where x indicates the case number starting from 1 and y denotes the answer of corresponding case.
 

Sample Input
31 2 11 22 361 2 1 3 2 11 21 32 42 53 6
 

Sample Output
Case #1: 6Case #2: 29
原创粉丝点击