• Codeforces 600 E. Lomsat gelral (dfs启发式合并map)


    题目链接:http://codeforces.com/contest/600/problem/E

    给你一棵树,告诉你每个节点的颜色,问你以每个节点为根的子树中出现颜色次数最多的颜色编号和是多少。

    最容易想到的是n*n的暴力,但是会超时。所以这里用到类似并查集的合并,对于每个子树颜色种数少的合并到颜色种数大的当中。

    不懂的看代码应该可以明白。

     1 //#pragma comment(linker, "/STACK:102400000, 102400000")
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <cstdlib>
     5 #include <cstring>
     6 #include <cstdio>
     7 #include <vector>
     8 #include <cmath>
     9 #include <ctime>
    10 #include <list>
    11 #include <set>
    12 #include <map>
    13 using namespace std;
    14 typedef long long LL;
    15 typedef pair <int, int> P;
    16 const int N = 1e5 + 5;
    17 map <int, int> cnt[N]; //first代表颜色编号,second代表出现次数
    18 map <int, LL> sum[N]; //first代表出现次数,second代表颜色编号之和
    19 LL ans[N];
    20 int head[N], tot, a[N];
    21 struct Edge {
    22     int next, to;
    23 }edge[N << 1];
    24 
    25 void init() {
    26     memset(head, -1, sizeof(head));
    27 }
    28 
    29 inline void add(int u, int v) {
    30     edge[tot].next = head[u];
    31     edge[tot].to = v;
    32     head[u] = tot++;
    33 }
    34 
    35 void dfs(int u, int p) {
    36     cnt[u][a[u]] = 1; //初始化:a[u]颜色出现一次
    37     sum[u][1] = (LL)a[u]; //初始化:出现一次的颜色之和为a[u]
    38     for(int i = head[u]; ~i; i = edge[i].next) {
    39         int v = edge[i].to;
    40         if(v == p)
    41             continue;
    42         dfs(v, u);
    43         if(cnt[u].size() < cnt[v].size()) { //颜色种类少的合并到颜色种类多的,u为颜色种类多的子树
    44             swap(cnt[u], cnt[v]);
    45             swap(sum[u], sum[v]);
    46         }
    47         for(auto it: cnt[v]) {
    48             cnt[u][it.first] += it.second; //it.first颜色出现次数合并累加
    49             int temp = cnt[u][it.first]; //temp为it.first颜色次数
    50             sum[u][temp] += (LL)it.first; //累加出现temp次的颜色
    51         }
    52         cnt[v].clear(); //清空
    53         sum[v].clear(); 
    54     }
    55     ans[u] = sum[u].rbegin()->second; //最大出现次数的颜色之和
    56 }
    57 
    58 int main()
    59 {
    60     init();
    61     int n, u, v;
    62     scanf("%d", &n);
    63     for(int i = 1; i <= n; ++i) {
    64         scanf("%d", a + i);
    65     }
    66     for(int i = 1; i < n; ++i) {
    67         scanf("%d %d", &u, &v);
    68         add(u, v);
    69         add(v, u);
    70     }
    71     dfs(1, -1);
    72     for(int i = 1; i <= n; ++i) {
    73         printf("%lld%c", ans[i], i == n? '
    ': ' ');
    74     }
    75     return 0;
    76 }
  • 相关阅读:
    快乐的深圳之旅
    编码和字体[zz]
    USB转串口芯片几点总结有疑问
    ANSI/UTF8/UCS2(UTF16),以及回车换行[zz]
    详细介绍四线电阻触摸屏的工作原理[zz]
    无字库12864液晶的驱动方法[zz]
    字符集和字符编码(Charset & Encoding)[zz]
    搭建CodeBlocks+wxWidgets可视化编程环境(Windows)
    wxWidgets初始化分析应用定义和初始化
    开发CodeBlocks插件(1)入门篇
  • 原文地址:https://www.cnblogs.com/Recoder/p/5844135.html
Copyright © 2020-2023  润新知