• CF600E Lomsat gelral 题解 树上启发式合并


    题目链接:https://codeforces.com/problemset/problem/600/E

    题目大意:求一个以 (1) 为根节点的有根树中每个节点对应的子树中出现次数最多的所有颜色的编号之和。

    解题思路:

    树上启发式合并。

    额外的处理(如何在 (O(1)) 时间内求出节点 (u) 当前对应的出现次数最多的节点编号之和):

    • (res[u]) 表示 (u) 对应的答案
    • (ap[i]) 表示目前出现次数等于 (i) 的颜色编号和
    • (apid) 表示目前出现次数最多的颜色的出现次数

    示例代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 100010;
    int n, m, sz[maxn], c[maxn], cnt[maxn];
    bool big[maxn];
    vector<int> g[maxn];
    
    void getsz(int u, int p) {
        sz[u] ++;
        for (auto v: g[u])
            if (v != p)
                getsz(v, u), sz[u] += sz[v];
    }
    
    long long res[maxn], ap[maxn];
    int apid;
    
    void add(int u, int p, int x) {
    
        int cc = cnt[ c[u] ];
        ap[cc] -= c[u];
        ap[cc+x] += c[u];
        if (x > 0 && apid < cc+x) apid = cc+x;
        if (x < 0 && cc == apid && ap[cc] == 0) apid --;
    
        cnt[ c[u] ] += x;
        for (auto v: g[u])
            if (v != p && !big[v])
                add(v, u, x);
    }
    void dfs(int u, int p, bool keep) {
        int mx = -1, bigSon = -1;   // mx表示重儿子的sz, bigSon表示重儿子编号
        for (auto v: g[u])
            if (v != p && sz[v] > mx)
                mx = sz[ bigSon = v ];
        for (auto v: g[u])
            if (v != p && v != bigSon)
                dfs(v, u, false);
    
        if (bigSon != -1)
            dfs(bigSon, u, true),
            big[bigSon] = true;
        add(u, p, 1);
        assert(apid > 0);
        res[u] = ap[apid];
        if (bigSon != -1)
            big[bigSon] = 0;
        if (!keep)
            add(u, p, -1);
    }
    int main() {
        cin >> n;
        for (int i = 1; i <= n; i ++) cin >> c[i];
        for (int i = 1; i < n; i ++) {
            int a, b;
            cin >> a >> b;
            g[a].push_back(b);
            g[b].push_back(a);
        }
        getsz(1, -1);
        dfs(1, -1, false);
        for (int i = 1; i <= n; i ++) cout << res[i] << " ";
        return 0;
    }
    
  • 相关阅读:
    算法之二叉树各种遍历
    File类基本操作之OutputStream字节输出流
    W3C DOM 事件模型(简述)
    Linux多线程编程小结
    linux下getsockopt和setsockopt具体解释及測试
    MyBatis入门学习(一)
    [ngRepeat:dupes] Duplicates in a repeater are not allowed. Use &#39;track by&#39; expression to specify uniq
    java中substring的使用方法
    Java Map遍历方式的选择
    E6全部刷机包
  • 原文地址:https://www.cnblogs.com/quanjun/p/13927713.html
Copyright © 2020-2023  润新知