codeforces-600E - Lomsat gelral(树上启发式合并)

链接:

http://codeforces.com/problemset/problem/600/E

题意:

You are given a rooted tree with root in vertex 1. Each vertex is coloured in some colour.

Let's call colour c dominating in the subtree of vertex v if there are no other colours that appear in the subtree of vertex v more times than colour c. So it's possible that two or more colours will be dominating in the subtree of some vertex.

The subtree of vertex v is the vertex v and all other vertices that contains vertex v in each path to the root.
求一个子数的众数和

思路:

考虑暴力算法,每次计算清零,复杂度n^2.
启发式合并,先处理出每个字节点的重儿子,和子树大小。
我们优先遍历每个子树的轻儿子,但是每次处理完后不保存记录的信息。
最后一次遍历重儿子,因为只剩重儿子,所以这个重儿子不需要清楚信息。
再统计子树的根节点时还要计算一边轻儿子。
总复杂度nlogn。不会证(逃

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 1e5+10;
const int MOD = 1e9+7;
const int INF = 1e9+10;

int n, num;
int size[MAXN], son[MAXN], dfn[MAXN];
int a[MAXN], b[MAXN], c[MAXN], col[MAXN];
LL mx, now, ans[MAXN];
vector<int> G[MAXN];

void dfs(int x, int fa)
{
    //计算子树大小,找重儿子
    size[x] = 1, dfn[x] = ++num;
    for (auto &y: G[x])
    {
        if (y == fa) continue;
        dfs(y, x);
        size[x] += size[y];
        son[x] = size[y] > size[son[x]] ? y : son[x];
    }
}

void add(int x)
{
    if (++c[x] > mx) mx = c[x], now = 0;
    if (c[x] == mx) now += x;
}

void solve(int x, int fa, int k)
{
    for (auto &y: G[x]) if (y != fa && y != son[x])
        solve(y, x, 0);
    if (son[x]) solve(son[x], x, 1);
    for (auto &y: G[x]) if (y != fa && y != son[x])
        for (int i = 0;i < size[y];i++) add(a[dfn[y]+i]);
    add(a[dfn[x]]);
    ans[x] = now;
    if (!k) for (int i = mx = now = 0;i < size[x];i++) c[a[dfn[x]+i]] = 0;
}

int main()
{
    //dsu on tree 启发式合并
    ios::sync_with_stdio(stdin);
    cin.tie(0), cout.tie(0);
    num = 0;
    cin >> n;
    for (int i = 1;i <= n;i++)
        cin >> col[i];
    for (int i = 1;i < n;i++)
    {
        int u, v;
        cin >> u >> v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(1, 0);
    for (int i = 1;i <= n;i++) a[dfn[i]] = col[i];
    solve(1, 0, 1);
    for (int i = 1;i <= n;i++)
        cout << ans[i] << ' ' ;

    return 0;
}

posted @ 2020-01-21 20:31  YDDDD  阅读(202)  评论(0编辑  收藏  举报