HDU-6035 Colorful Tree(dfs序造树)

来源:互联网 发布:淘宝服务市场怎么投诉 编辑:程序博客网 时间:2024/06/14 21:21

题意;

每条路径的权值是:路径上经过的不同颜色节点的个数。

询问各个点互达后的路径权值总和

思路: 看了小半天才看懂。。。

首先解释下官方题解的意思。

对于所求的问题,可以转化为每种颜色对于答案可以贡献多少次值(颜色i对于在所有路径中出现了几次)。

颜色i贡献次数=所有路径-路径中未出现颜色i的路径条数。

之后把所有的颜色i相加即可。

代码中;siz表示以当前节点为根,子树大小

      sum表示以颜色i为节点的,所有子树大小

每次在dfs时,因先遍历其子树,所以sum[col[u]] 有可能会增加,而与之前未增加时候(第一次到u) 的sum[col[u]]做差就是在v节点中,以颜色col[u]为根的子树的总大小。

tmp=siz[v]-sonu 就是在v子树中 除u颜色之外的节点个数。

ans在这时减去tmp的组合就是在此不通过col[u]节点的连通块中的边的条数。

之后在main函数时 ans减去的值是有可能某些节点在颜色i的父亲等较高位置,因此sum[i]无法统计到,这是上层的连通块数量也是颜色i无法贡献的,所以也应该减去!!

#include <bits/stdc++.h>using namespace std;const int maxn=2e5+5;vector< int >vec[maxn];int siz[maxn];int vis[maxn];int col[maxn];int sum[maxn];typedef long long ll;ll ans,n;void dfs(int u,int fa){    siz[u]=1;    int pre=sum[col[u]];    int add=0;    for(int i=0;i<vec[u].size();i++)    {        int v=vec[u][i];        if(v==fa)            continue;        dfs(v,u);        siz[u]+=siz[v];        ll sonu=sum[col[u]]-pre;//表示在子树v中,以颜色col[u]为根的子树总大小        ll tmp=siz[v]-sonu;     //表示在子树v中,除了u颜色之外的节点个数        add+=sonu;              //add记录当前所有子树中以col[u]为根的节点总数        ans-=tmp*(tmp-1)/2;     //表示v子树中,各个节点互相到达,无需进过col[u]        pre=sum[col[u]];        //表示记录上一次的sum    }    sum[col[u]]+=siz[u]-add;//sum[col[u]]加上以u为根,属于这个节点的连通块的节点总数}int main(){    int cs=1;    while(~scanf("%lld",&n))    {        memset(sum,0,sizeof(sum));        memset(col,0,sizeof(col));        memset(siz,0,sizeof(siz));        memset(vis,0,sizeof(vis));        int cnt=0;        for(int i=1;i<=n;i++)        {            scanf("%d",&col[i]);            if(!vis[col[i]])                vis[col[i]]=1,cnt++;        }        int u,v;        for(int i=1;i<=n;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=cnt*(n)*(n-1)/2;        dfs(1,0);        for(int i=1;i<=n;i++)        {            if(!sum[i])                continue;            ll res=n-sum[i];            ans-=(res-1)*res/2;//此步骤减去的是 在i颜色节点的 上面部分,有n-sum[i]个节点,这些节点互通不需要经过i颜色节点。        }        printf("Case #%d: %lld\n", cs++, ans);    }}/*21 21 2*/


原创粉丝点击