Codeforces 600E Lomsat gelral (启发式合并)

来源:互联网 发布:mindnode有windows版么 编辑:程序博客网 时间:2024/05/20 06:08

Codeforces 600E Lomsat gelral (启发式合并)

题目大意:
一棵树,每个点有一个颜色,每一次询问在u节点为根的子树中,颜色出现次数最多的那些颜色的和。
考虑启发式合并,每个节点开map,cnt[u][i]表示u节点为根的子树上,i颜色在出现多少次,sum[u][i]表示在当前子树中,恰好出现了i次的颜色和。
每次把小的插入到大的里边,修改cnt,sum
合并复杂度O(nlogn), map的复杂度O(logn), 总复杂度O(nlog2n)

#include <map>#include <cstdio>#include <cstring>#include <iostream>#include <vector>#include <algorithm>#define LL long long#define N 100010using namespace std;struct Edge{    int to, nxt;}ed[N << 1];int n, idc=0;int head[N];int col[N];LL ans[N];map<int, int> cnt[N];map<int, LL> sum[N];void adde(int u,int v){    ed[++idc].to = v;    ed[idc].nxt = head[u];    head[u] = idc;}void dfs(int u,int fa){    cnt[u].clear(); sum[u].clear();    cnt[u][col[u]] = 1;    sum[u][1] = col[u];    for(int i=head[u]; i; i=ed[i].nxt){        int v = ed[i].to;        if(v == fa) continue;        dfs(v, u);        if(cnt[u].size() < cnt[v].size()){            swap(cnt[u], cnt[v]);            swap(sum[u], sum[v]);        }        for(map<int,int>::iterator it=cnt[v].begin(); it!=cnt[v].end(); it++){            int x = it->first, y = it->second;            if( cnt[u].count(x) ){                sum[u][cnt[u][x]] -= x;                cnt[u][x] += y;                sum[u][cnt[u][x]] += x;            }            else{                cnt[u][x] = y;                sum[u][cnt[u][x]] += x;            }        }    }    map<int, LL>::iterator it = sum[u].end(); it--;    ans[u] = it->second;//最大次数颜色和 }void init(){    idc = 0;    memset(head, 0, sizeof(head));    memset(ed, 0, sizeof(ed));}int main(){    while( scanf("%d", &n) != EOF ){        init();        for(int i=1; i<=n; i++) scanf("%d", &col[i]);        for(int i=1; i<n; i++){            int u, v; scanf("%d%d", &u, &v);            adde(u, v); adde(v, u);        }        dfs(1, 1);        for(int i=1; i<=n; i++) printf("%I64d ", ans[i]);    }    return 0;}
原创粉丝点击