zoukankan      html  css  js  c++  java
  • HDU6035 Colorful Tree

    题目链接:https://vjudge.net/problem/HDU-6035

    题目大意:

      多样例输入。

      对于每一个样例,给出 n ((2 le n le 200000)) 个结点的一棵树,各个节点都有各自的颜色 (c_i  (1 le c_i le n)),树上任意两点之间的路径的权值为该路径经过的不同颜色的结点数,求树上所有两点路径的权值之和。

    知识点:  树、DFS

    解题思路:

      求树上所有的两点路径的权值之和,可以转化为求各个颜色在各条路径中的贡献值(即该颜色能够为树上的各条路径增加的权值的总和,也可以理解成是该颜色在多少条路径中出现)。但是,并没有非常好的方法可以直接求出这个总的贡献值,于是,我们可以反过来求:各个颜色在多少条路径中没有出现。


      如图1所示,树上所有的红色结点将整棵树分成了 5 个联通块(笔者已用 1~5 标出),则这五个联通块里面的所有路径显然都没有经过红色结点。其实这些联通块也可以看成是一棵子树,对于一棵有 n 个结点的树,树上所有路径数为 (frac{n(n-1)}{2}) 1

      那么,我们所要求的答案其实就是(frac{NumberOfColors imes n imes (n-1)}{2}) - 没有经过各个颜色的所有路径数

      对于每一种颜色,没有经过该种颜色的路径可以分成两类:

      1、从树根以下,到第一次接触颜色点之前的这一联通块的路径(如图1中的第1块);

      2、颜色点之间和颜色点以下直到叶子的联通块(如图1中的第2~5块)。

      只要算出这两种路径的总数,即可求出答案,但此题的实现并不简单,请看代码及注释:

    AC代码:

     1 #include <cstdio>
     2 #include <vector>
     3 #include <set>
     4 
     5 using namespace std;
     6 typedef long long ll;
     7 const int maxn=200000+5;
     8 
     9 int color[maxn];//记录各个结点的颜色
    10 ll sum[maxn];//精髓所在
    11 ll sizes[maxn];//记录各个结点以下的结点数
    12 vector<int> tree[maxn];//记录树
    13 set<int> col;
    14 ll ans;
    15 void find_size(int fa,int gfa){//找出各点的 sizes[i]
    16     sizes[fa]=1;
    17     for(int i=0;i<tree[fa].size();i++){
    18         if(tree[fa][i]==gfa)    continue;
    19         find_size(tree[fa][i],fa);
    20         sizes[fa]+=sizes[tree[fa][i]];
    21     }
    22 }
    23 void find_ans(int fa,int gfa){
    24     ll tmp=0;
    25     if(sum[color[fa]]!=0){  
    26 //此处 sum[color[fa]] 记录的是目前已知的从各个分枝的第一个颜色为 color[fa] 的点到叶子的结点数,那么当最后求出这个值以后,上文提及的第一类路径的结点数即为 n-sum[i] 
    27         tmp=sum[color[fa]];    
    28         sum[color[fa]]=0;
    29 /*      *****************       */
    30     }
    31     for(int i=0;i<tree[fa].size();i++){
    32         if(tree[fa][i]==gfa)    continue;
    33         find_ans(tree[fa][i],fa);
    34 //此处sum[color[fa]]用于求从 tree[fa][i] 这个结点出发到下一个颜色为 color[fa] 或者叶子的联通块的结点数
    35 //请注意上下两处划线处的代码
    36         ans-=(sizes[tree[fa][i]]-sum[color[fa]])*(sizes[tree[fa][i]]-sum[color[fa]]-1)/2;
    37         sum[color[fa]]=0;
    38 /*      *****************       */
    39     }sum[color[fa]]=sizes[fa]+tmp;
    40 }
    41 int main(){
    42     int n,a,b;
    43     int kase=1;
    44     while(scanf("%d",&n)==1){
    45         col.clear();
    46         for(int i=1;i<=n;i++){
    47             sum[i]=0;
    48             tree[i].clear();
    49         }
    50         for(int i=1;i<=n;i++){
    51             scanf("%d",&color[i]);
    52             col.insert(color[i]);
    53         }
    54         ans=(ll)col.size()*n*(n-1)/2;
    55         for(int i=1;i<n;i++){
    56             scanf("%d%d",&a,&b);
    57             tree[a].push_back(b);
    58             tree[b].push_back(a);
    59         }find_size(1,0);
    60         find_ans(1,0);
    61         set<int>::iterator pt=col.begin();
    62         for(;pt!=col.end();pt++){
    63             int cl=*pt;
    64             ans-=(n-sum[cl])*(n-sum[cl]-1)/2;
    65         }
    66         printf("Case #%d: %lld
    ",kase++,ans);
    67     }return 0;
    68 }

      

      

    1、n(n-1)/2——此处的公式可能会挂,原因不明......

    “这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
  • 相关阅读:
    Ubuntu上安装RabbitMQ
    解决tfs工作区绑定问题
    ubuntu装个nginx
    supervisor执行dotnet
    Validate + Boostrap tooltip 表单验证示例
    ASP.NET下跨应用共享Session和使用Redis进行Session托管
    IE下将网页拷贝到剪贴板
    js格式化json格式的日期
    js 时间戳转换
    Windows服务简单使用
  • 原文地址:https://www.cnblogs.com/Blogggggg/p/7825693.html
Copyright © 2011-2022 走看看