【CF600E】 Lomsat gelral

CF600E Lomsat gelral


Solution

考虑一下子树的问题,我们可以把一棵树的dfn序搞出来,那么子树就是序列上的一段连续的区间.

然后就可以莫队飞速求解了.

但是这题还有\(\Theta(nlog_n)\)的做法.能有\(\Theta(n\sqrt{n})\)的做法要什么\(logn\)

考虑\(dsu\ on\ tree\),与莫队没有任何区别.

如果不会的话,请自行跳转小Z的袜子并且切掉.

代码实现

#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=100010;
int n,front[N],nxt[N<<1],to[N<<1],cnt,siz[N],son[N],num[N],c[N],Max,b[N];
long long ans[N];
pair<int,long long>f[N];
void Add(int u,int v){to[++cnt]=v;nxt[cnt]=front[u];front[u]=cnt;}
void dfs(int u,int fa){
	siz[u]=1;
	for(int i=front[u];i;i=nxt[i]){
		int v=to[i];
		if(v==fa)continue;
		dfs(v,u);siz[u]+=siz[v];
		if(siz[v]>siz[son[u]])son[u]=v;
	}
}
void add(int u,int fa,int opt){
	int &p=num[c[u]];
	f[p].first--;f[p].second-=c[u];
	p+=opt;
	f[p].first++;f[p].second+=c[u];
	if(opt==1)Max=max(Max,p);
	else if(!f[Max].first)Max--;
	for(int i=front[u];i;i=nxt[i])
	{
		int v=to[i];
		if(v!=fa && !b[v])add(v,u,opt);
	}
}
void dfs(int u,int fa,int opt){
	for(int i=front[u];i;i=nxt[i]){
		int v=to[i];
		if(v!=fa && v!=son[u])dfs(v,u,0);
	}
	if(son[u])dfs(son[u],u,1);b[son[u]]=1;
	add(u,fa,1);
	ans[u]=f[Max].second;
	b[son[u]]=0;
	if(!opt)add(u,fa,-1);
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&c[i]);
	for(int i=1;i<n;i++){
		int u,v;scanf("%d%d",&u,&v);
		Add(u,v);Add(v,u);
	}
	dfs(1,1);dfs(1,1,1);
	for(int i=1;i<=n;i++)printf("%lld%c",ans[i],i==n?'\n':' ');
	return 0;
}
posted @ 2019-01-25 09:06  QwQGJH  阅读(155)  评论(2编辑  收藏  举报