您的位置:首页 > 其它

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

2017-07-06 11:45 337 查看
点击打开链接

题意: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
,ans
;
map<int,int> col
;//col[u][x] ×ÓÊ÷uÖÐÑÕÉ«xµÄ³öÏÖ´ÎÊý
map<int,ll> sum
;//sum[u]
vector<int> e
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: