600E:Lomsat gelral
题意简述
给出一棵节点数为
n
的树,树上每个节点有一种特征值
数据范围
1≤ci≤n≤105
思路
树链剖分。
启发式合并,轻链向重链合并。
每个节点最多合并
logn
次。
维护每种特征的个数,个数的特征值的和。
时间复杂度
O(nlogn)
代码
#include<cstdio>
#include<cstring>
using namespace std;
struct edge{
int s,t,next;
}e[200010];
int head[100010],cnt;
void addedge(int s,int t)
{
e[cnt].s=s;e[cnt].t=t;e[cnt].next=head[s];head[s]=cnt++;
e[cnt].s=t;e[cnt].t=s;e[cnt].next=head[t];head[t]=cnt++;
}
int n,u,v,mx;
int size[100010],son[100010],c[100010],num[100010];
long long ans[100010],sum[100010];
bool ski[100010];
void dfs(int node,int lastfa)
{
size[node]=1;
for (int i=head[node];i!=-1;i=e[i].next)
if (e[i].t!=lastfa)
{
dfs(e[i].t,node);
size[node]+=size[e[i].t];
if (size[e[i].t]>size[son[node]])
son[node]=e[i].t;
}
}
void modify(int node,int lastfa,int val)
{
num[c[node]]+=val;
sum[num[c[node]]-val]-=c[node];
sum[num[c[node]]]+=c[node];
if (num[c[node]]>mx)
mx=num[c[node]];
if (!sum[num[c[node]]-val]&&num[c[node]]-val==mx)
mx--;
for (int i=head[node];i!=-1;i=e[i].next)
if (e[i].t!=lastfa&&!ski[e[i].t])
modify(e[i].t,node,val);
}
void dfs2(int node,int lastfa,bool keep)
{
for (int i=head[node];i!=-1;i=e[i].next)
if (e[i].t!=lastfa&&e[i].t!=son[node])
dfs2(e[i].t,node,0);
if (son[node])
{
dfs2(son[node],node,1);
ski[son[node]]=1;
}
modify(node,lastfa,1);
ans[node]=sum[mx];
ski[son[node]]=0;
if (!keep)
modify(node,lastfa,-1);
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&c[i]);
memset(head,0xff,sizeof(head));
cnt=0;
for (int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
addedge(u,v);
}
dfs(1,1);
dfs2(1,1,1);
for (int i=1;i<=n;i++)
printf("%I64d ",ans[i]);
return 0;
}