codeforces 600E E. Lomsat gelral

传送门:https://codeforces.com/contest/600/problem/E

题意:

给你一颗n个节点的树,树上的每一个节点都有一种颜色,询问每一个节点所在的子树颜色数量最多的那些颜色的值的总和

题解:

考虑暴力做法,用一个数组能表示出所有状态。然后合并状态进行考虑,那么对于每个节点开一个这样的数组,明显空间不够。那么就动态开点,那么对于合并,数组合并o(n),考虑线段树合并。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N = 1e5 + 10;
const int M = 2e5 + 10;

int n;
int h[N], e[M], ne[M], idx;

struct node
{
    ll dat, cnt;
    int l, r;
}tr[N * 30];

int root[N], tot;
ll w[N], ans[N];

void add(int a, int b)
{
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx ++;
}

void update(int p)
{
    if(tr[tr[p].l].cnt > tr[tr[p].r].cnt)
    {
        tr[p].cnt = tr[tr[p].l].cnt;
        tr[p].dat = tr[tr[p].l].dat;
        return ;
    }
    else if(tr[tr[p].l].cnt < tr[tr[p].r].cnt)
    {
        tr[p].cnt = tr[tr[p].r].cnt;
        tr[p].dat = tr[tr[p].r].dat;
        return ;
    }
    else
    {
        tr[p].cnt = tr[tr[p].l].cnt;
        tr[p].dat = tr[tr[p].l].dat + tr[tr[p].r].dat;
        return ;
    }
}

void insert(int &p, int l, int r, int c)
{
    if(!p) p = ++ tot;
    if(l == r)
    {
        tr[p].cnt ++;
        tr[p].dat = c;
        return ;
    }
    int mid = l + r >> 1;
    if(c <= mid) insert(tr[p].l, l, mid, c);
    else insert(tr[p].r, mid + 1, r, c);
    update(p);
}

int merge(int p, int q, int l, int r)
{
    if(!p) return q;
    if(!q) return p;
    if(l == r)
    {
        tr[p].cnt += tr[q].cnt;
        return p;
    }
    int mid = l + r >> 1;
    tr[p].l = merge(tr[p].l, tr[q].l, l, mid);
    tr[p].r = merge(tr[p].r, tr[q].r, mid + 1, r);
    update(p);
    return p;
}

void dfs(int x, int fa)
{
    insert(root[x], 1, n, w[x]);
    for (int i = h[x]; ~i; i = ne[i])
    {
        int j = e[i];
        if(j == fa) continue;
        dfs(j, x);
        root[x] = merge(root[x], root[j], 1, n);
    }
    ans[x] = tr[root[x]].dat;
}

int main()
{
    memset(h, -1, sizeof(h));
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++)
        scanf("%lld", &w[i]);
    for (int i = 0; i < n - 1; i ++)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        add(a, b), add(b, a);
    }
    dfs(1, -1);
    for (int i = 1; i <= n; i ++)
    {
        printf("%lld%c", ans[i], i == n? '\n' : ' ');
    }
}
12-23 00:47