Codeforces 600E Lomsat gelral 树上启发式合并

来源:互联网 发布:mac os 显示内容放大 编辑:程序博客网 时间:2024/06/04 19:12

点击打开链接

题意:n个结点的树,每个结点颜色为c[i].n<=1e5,求每个结点的子树中颜色出现次数最多的颜色之和.

启发式合并:一个元素从一个集合被加入另一个集合时, 所在集合的规模至少扩大一倍. 如果没有分离操作且元素数目有限, 合并的次数是logn的.

设两个map<int,ll>:col[u][x] 子树u中颜色x的出现次数,sum[u][x] 子树u中出现次数为x的颜色之和
dfs时,根据u的子树v来更新col[u][x],暴力更新O(n^2)


size小的合并到大的 每个元素合并时 新的map size至少为原来两倍,所以每个元素最多合并logn次 合并次数为nlogn 每次合并log 时间复杂度O(n(logn)^2)

#include <bits/stdc++.h>using namespace std;typedef long long ll;typedef pair<int,int> ii;const ll mod=1e9;const ll inf=1e18;const int N=2e5+20;ll n,c[N],ans[N];map<int,int> col[N];//col[u][x] ×ÓÊ÷uÖÐÑÕÉ«xµÄ³öÏÖ´ÎÊý map<int,ll> sum[N];//sum[u]vector<int> e[N];void merge(int u,int v){if(col[u].size()<col[v].size())//swap(col[u],col[v]),swap(sum[u],sum[v]);for(map<int,int>::iterator it=col[v].begin();it!=col[v].end();it++){sum[u][col[u][it->first]]-=it->first;col[u][it->first]+=col[v][it->first];sum[u][col[u][it->first]]+=it->first;}}void dfs(int u,int fa){col[u][c[u]]=1;sum[u][1]=c[u];for(int i=0;i<e[u].size();i++){int v=e[u][i];if(v==fa)continue;dfs(v,u);merge(u,v);}ans[u]=sum[u].rbegin()->second;}int main(){while(cin>>n){int u,v;for(int i=1;i<=n;i++)scanf("%d",&c[i]),e[i].clear();for(int i=1;i<=n-1;i++){scanf("%d%d",&u,&v);e[u].push_back(v);e[v].push_back(u);}dfs(1,-1);for(int i=1;i<=n;i++)printf("%I64d%c",ans[i],i==n?'\n':' ');}return 0;}


阅读全文
0 0
原创粉丝点击