题目链接

题目大意:给出一颗含有$n$个结点的树,每个节点有一个颜色。求树中每个子树最多的颜色的编号和。

-------------------------

树上启发式合并(dsu on tree)。

我们先考虑暴力怎么做。遍历整颗树,暴力枚举子树然后用桶维护颜色个数。这样做是$O(n^2)$的,显然会T。我们需要一种更快的算法:树上启发式合并。

关于启发式算法的介绍,详见OI Wiki。本文只介绍树上启发式合并算法。本题的解法:

每处理完一颗子树,我们都要把桶清空一次,以免对它的兄弟造成影响。而这样做还要从它的祖先遍历一遍,浪费时间。

我们发现:遍历最后一颗子树时,桶是不用清空的。因为遍历完那颗子树后可以直接把答案加入$ans$中。那我们肯定选重儿子啊,省时省力。遍历轻儿子相对不费事。

看起来是不是没有快多少?实际上它是$O(n\log n)$的。下面是证明:

对于每个节点,它被计算的次数就是它到根节点路径的轻边个数。

而结点往上跳一次,子树大小至少为原来两倍,所以轻边个数最多是$\log n$。所以时间复杂度$O(n\log n)$。

证明过程跟树链剖分的有点像。

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,color[],bucket[],ans[];
int size[],son[],sum,mx;
int head[],cnt;
struct node
{
int next,to;
}edge[];
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)){if (ch=='-') f=-;ch=getchar();}
while(isdigit(ch)){x=x*+ch-'';ch=getchar();}
return x*f;
}
inline void add(int from,int to)
{
edge[++cnt].next=head[from];
edge[cnt].to=to;
head[from]=cnt;
}
inline void dfs_son(int now,int fa)
{
size[now]=;
int mx=,p=;
for (int i=head[now];i;i=edge[i].next)
{
int to=edge[i].to;
if (to==fa) continue;
dfs_son(to,now);
size[now]+=size[to];
if (size[to]>mx)
{
mx=size[to];
p=to;
}
}
if (p) son[p]=;
}
void getans(int x,int f,int p){
bucket[color[x]]++;
if(bucket[color[x]]>mx){
mx=bucket[color[x]];
sum=color[x];
}else if(bucket[color[x]]==mx)sum+=color[x];
for(int i=head[x];i;i=edge[i].next){
int y=edge[i].to;
if(y==f || y==p)continue;
getans(y,x,p);
}
}
inline void init(int now,int fa)
{
bucket[color[now]]--;
for (int i=head[now];i;i=edge[i].next)
{
int to=edge[i].to;
if (to==fa) continue;
init(to,now);
}
}
inline void dfs(int now,int fa)
{
int p=;
for (int i=head[now];i;i=edge[i].next)
{
int to=edge[i].to;
if (to==fa) continue;
if (!son[to])
{
dfs(to,now);
init(to,now);
sum=mx=;
}
else p=to;
}
if (p) dfs(p,now);
getans(now,fa,p);
ans[now]=sum;
}
signed main()
{
n=read();
for (int i=;i<=n;i++) color[i]=read();
for (int i=;i<n;i++)
{
int x=read(),y=read();
add(x,y);add(y,x);
}
dfs_son(,);
dfs(,);
for (int i=;i<=n;i++) printf("%lld ",ans[i]);
return ;
}

【CF600E】Lomset gelral 题解(树上启发式合并)的更多相关文章

  1. [Codeforces600E] Lomsat gelral(树上启发式合并)

    [Codeforces600E] Lomsat gelral(树上启发式合并) 题面 给出一棵N个点的树,求其所有子树内出现次数最多的颜色编号和.如果多种颜色出现次数相同,那么编号都要算进答案 N≤1 ...

  2. Codeforces 600E - Lomsat gelral(树上启发式合并)

    600E - Lomsat gelral 题意 给出一颗以 1 为根的树,每个点有颜色,如果某个子树上某个颜色出现的次数最多,则认为它在这课子树有支配地位,一颗子树上,可能有多个有支配的地位的颜色,对 ...

  3. Codeforces 600E Lomsat gelral (树上启发式合并)

    题目链接 Lomsat gelral 占坑……等深入理解了再来补题解…… #include <bits/stdc++.h> using namespace std; #define rep ...

  4. 【学习笔记/题解】树上启发式合并/CF600E Lomsat gelral

    题目戳我 \(\text{Solution:}\) 树上启发式合并,是对普通暴力的一种优化. 考虑本题,最暴力的做法显然是暴力统计每一次的子树,为了避免其他子树影响,每次统计完子树都需要清空其信息. ...

  5. CF EDU - E. Lomsat gelral 树上启发式合并

    学习:http://codeforces.com/blog/entry/44351 E. Lomsat gelral 题意: 给定一个以1为根节点的树,每个节点都有一个颜色,问每个节点的子树中,颜色最 ...

  6. dsu on tree 树上启发式合并 学习笔记

    近几天跟着dreagonm大佬学习了\(dsu\ on\ tree\),来总结一下: \(dsu\ on\ tree\),也就是树上启发式合并,是用来处理一类离线的树上询问问题(比如子树内的颜色种数) ...

  7. 树上启发式合并(dsu on tree)学习笔记

    有丶难,学到自闭 参考的文章: zcysky:[学习笔记]dsu on tree Arpa:[Tutorial] Sack (dsu on tree) 先康一康模板题吧:CF 600E($Lomsat ...

  8. 神奇的树上启发式合并 (dsu on tree)

    参考资料 https://www.cnblogs.com/zhoushuyu/p/9069164.html https://www.cnblogs.com/candy99/p/dsuontree.ht ...

  9. dsu on tree (树上启发式合并) 详解

    一直都没出过算法详解,昨天心血来潮想写一篇,于是 dsu on tree 它来了 1.前置技能 1.链式前向星(vector 建图) 2.dfs 建树 3.剖分轻重链,轻重儿子 重儿子 一个结点的所有 ...

随机推荐

  1. C++求树子节点权重最大的和

    #include <iostream> #include <vector> using namespace std; int n; const int MaxN = 1e5; ...

  2. 获取本机SqlServer名称

    using System.Data.Sql; //检索包含有关可用SQL Server实例的信息的表,必须先使用共享/静态Instance属性来检索枚举器 SqlDataSourceEnumerato ...

  3. shell专题(八):read读取控制台输入

    1.基本语法 read(选项)(参数) 选项: -p:指定读取值时的提示符: -t:指定读取值时等待的时间(秒). 参数 变量:指定读取值的变量名 2.案例实操 (1)提示7秒内,读取控制台输入的名称 ...

  4. 基于animate.css动画库的全屏滚动小插件,适用于vue.js(移动端、pc)项目

    功能简介 基于animate.css动画库的全屏滚动,适用于vue.js(移动端.pc)项目. 安装 npm install vue-animate-fullpage --save 使用 main.j ...

  5. nexus 安装与启动(windows本版)

    1.下载 https://www.sonatype.com/download-oss-sonatype 本人云盘:https://pan.baidu.com/s/1_Qmhzij0TlOmTGT-eb ...

  6. Istio安全-认证(istio 系列七)

    Istio安全-认证 目录 Istio安全-认证 认证策略 配置 自动mutual TLS 全局启用istio的mutual TLS STRIC模式 卸载 针对单个命名空间或负载启用mutual TL ...

  7. java 将整型数组转化为字符串

    java arrays 和arrayList 的区别 package com.vc; import java.util.Arrays; public class Demo05 { public sta ...

  8. 用x种方式求第n项斐波那契数,99%的人只会第一种

    大家好啊,我们又见面了.听说有人想学数据结构与算法却不知道从何下手?那你就认真看完本篇文章,或许能从中找到方法与技巧.     本期我们就从斐波那契数列的几种解法入手,感受算法的强大与奥妙吧. 原文链 ...

  9. leetcode题库练习_左旋转字符串

    题目:左旋转字符串 字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部.请定义一个函数实现字符串左旋转操作的功能.比如,输入字符串"abcdefg"和数字2,该函数将返 ...

  10. 超详细windows安装mongo数据库、注册为服务并添加环境变量

    1.官网下载zip安装包 官网地址https://www.mongodb.com/download-center/community?jmp=nav,现在windows系统一般都是64位的,选好版本. ...