hdu 6035(Colorful Tree)

参考题解做的!思路+题意 在代码中藏着呢。

  1 #include <stdio.h>
  2 #include <iostream>
  3 #include <algorithm>
  4 #include <string.h>
  5 #include <math.h>
  6 #include <string>
  7 
  8 
  9 using namespace std;
 10 typedef long long int LL;
 11 const int MOD= 1e9+7;
 12 const int INF=2e9+1e8;
 13 
 14 
 15 const int maxn=200000+1000;
 16 /**
 17  * 数据定义部分
 18  */
 19 struct Node 
 20 {
 21     int to,next;
 22 }edge[maxn*2];
 23 int first[maxn],sz,color[maxn];
 24 
 25 void addedge(int s,int t)
 26 {
 27     edge[sz].to=t,edge[sz].next=first[s];
 28     first[s]=sz++;
 29 }
 30 
 31 LL cnt;
 32 LL size[maxn],sum[maxn];
 33 /**
 34  * sum[i] 是一个维护的数组,表示当前i颜色的此时i颜色为子树的根的子树的大小;
 35  */
 36 void dfs(int x,int pre)
 37 {
 38     size[x]=1;
 39     int all=0;
 40     int last=sum[color[x]];
 41     for(int i=first[x];i!=-1;i=edge[i].next)
 42     {
 43         int to=edge[i].to;
 44         if(to==pre) continue;
 45         dfs(to,x);
 46         size[x]+=size[to];
 47         LL delta=sum[color[x]]-last;//delta 是变化量
 48         LL tmp=size[to]-delta;//子树大小-变化量 就是 子树联通块大小;
 49         last=sum[color[x]];
 50         cnt+=tmp*(tmp-1)/2;
 51         all+=size[to]-delta;
 52     }
 53     sum[color[x]]+=all+1;
 54 }
 55 /**
 56  * 题目意思:给定一棵树,树节点编号为1~n,树上的节点有颜色,颜色范围也是1~n。
 57  * 定义一个值:树上任意不同两个节点路径上的不同颜色的个数(也就是颜色的种类数)。
 58  * 求所有的任意两个点的这个值的和是多少?有n*(n-1)/2种值,需要加起来。
 59  * 
 60  * 大致思路:求不同路径的颜色种类和;
 61  * 对于每种颜色考虑:有多少条路径含有这种颜色,再把每种颜色的加起来就是
 62  * 最终答案;
 63  * 反过来思考颜色:有多少条路径不包含这种颜色,求和,假设求和后值为 sum。
 64  * 那么最终答案就是:颜色总共的种类数×(n*(n-1)/2)-sum;
 65  * 那么sum怎么求?我们先只考虑一种颜色,我们考虑的颜色这个点会将树分割开成多个子树,
 66  * 多个子树内部之间路径是不包含这种颜色的;dfs子树节的时候,遇到的节点颜色就是需要处理的
 67  * 每个子树的路径数量:假设这个子树有k个节点,那么就是k*(k-1)/2;
 68  */
 69 
 70  /**
 71   * 代码具体实现:
 72   * size[i]代表i号节点的子树的节点数量,
 73   */
 74 
 75 int vis[maxn];
 76 int main()
 77 {
 78     int cas=1,n;
 79     while(scanf("%d",&n)+1)
 80     {
 81         LL total=0;
 82         memset(vis,0,sizeof(vis));
 83         sz=0;
 84         memset(first,-1,sizeof(first));
 85         memset(sum,0,sizeof(sum));
 86         for(int i=1;i<=n;i++) 
 87         {
 88             scanf("%d",&color[i]);
 89             if(vis[color[i]]==0)
 90             {
 91                 total++;
 92                 vis[color[i]]=1;
 93             }
 94         }
 95         for(int i=1;i<n;i++)
 96         {
 97             int x,y;
 98             scanf("%d%d",&x,&y);
 99             addedge(x,y);
100             addedge(y,x);
101         }
102         cnt=0;
103         dfs(1,1);
104         for(int i=1;i<=n;i++)
105         {
106             if(vis[i]&&i!=color[1])
107             {
108                 LL  temp=n-sum[i];
109                 cnt+=temp*(temp-1)/2;
110             }
111         }
112         printf("Case #%d: %lld\n",cas++,total*n*(n-1)/2-cnt);
113     }
114     return 0;
115 }

 

posted @ 2017-07-27 09:34  Code-dream  阅读(349)  评论(0编辑  收藏  举报