树上启发式合并 洛谷U41492

洛谷U41492 树上数颜色 树上启发式合并 题目链接:https://www.luogu.com.cn/problem/U41492 题意:给一棵根为1的树,每次询问子树颜色种类数 思路:树上启发式合并,每次计算时如果是第一次出现就计算贡献,轻链的话要消除贡献 #include<bits/stdc++.h> using namespace std; typedef long long ll; #define fi first #define se second #define ls rt << 1 #define rs . 阅读详情

对于子树类不修改的问题,比如说统计所有子树的颜色种类数,以下面这个样例为例子:

要统计以u为根的子树,应该暴力统计u的各个子树之和。流程应该是这样:假设规模为一个三个结点的二叉树,u为根,v1,v2为两个叶子节点,暴力统计以v1为根的节点,然后清空统计数组,再暴力统计以v2为根的节点,然后再清空数组,统计u为根的子树。我们可以发现,是因为两棵子树一定毫不相干我们才清空,但是v2与u不是毫不相干的,他们是包含关系的,所以我们可以保留v2的,那么在统计u的时候就可以不统计v2的了。更一般地,应该是保留u的最后一个儿子,节省统计u的时间,为了最大化节省的时间,我们就把重儿子放在最后一个(因为重儿子节点数最多,最耗时间),所以实际算法为了确保轻儿子一定在统计的前面,我们就一路轻儿子递归至叶子,再自底向根的回溯式统计。

统计代码:

void get_light_son(int u,int hson,int fa,int k)//统计轻儿子
{
	cnt[color[u]]+=k;
	if(k>0&&cnt[color[u]]==1) tot++;//一定要有k>0,因为可以从0->1也可以2->1,会多计数,只统计增加时的1
	if(k<0&&cnt[color[u]]==0) tot--;//同上
	for(int i=head[u];i;i=edge[i].next)
	{
		int v=edge[i].to;
		if((k==1&&v==hson)||v==fa) continue;//如果v是fa或者是在增加的时候v是重儿子(被保留在cnt数组了,不需要再记录),跳过
		get_light_son(v,hson,u,k);//递归的时候hson还是hson,因为我们只是不统计根的重儿子,即一开始传入的hson
	}
}

void dfs(int u,int fa)
{
	for(int i=head[u];i;i=edge[i].next)
	{
		int v=edge[i].to;
		if(v!=fa&&v!=son[u]) dfs(v,u); //一路遍历轻儿子到叶子
	}
	if(son[u]) dfs(son[u],u);//重儿子放在最后统计
	get_light_son(u,son[u],fa,1);//计数这个节点为根的子树的所有节点,因为这个节点的重儿子被最后留下在cnt数组了,所以在内部特判重儿子,不记录
	ans[u]=tot;//以u为根的子树就是原先保留的重儿子加上get_light_son()的轻儿子记录,tot记录种数
	if(u!=son[fa]) get_light_son(u,son[u],fa,-1);//这个节点不是fa的重儿子,直接清空记录
}

其余就是链式前向星和统计树链剖分求重儿子的常规操作。

树上启发式合并的复杂度是O(nlogn)的。证明待补。

完整代码:

#include<iostream>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<cctype>
#include<algorithm>
#include<string>
#include<vector>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<deque>
#define ll long long
#define ull unsigned long long
#define fr first
#define se second
#define endl '\n'
using namespace std;

const int inf=0x3fffffff;
const long long INF=0x3f3f3f3f3f3f;
const double eps=1e-8;
const double pi=2*acos(0.0);

template<typename T>
T father(T x){return x&1?x-1>>1:x>>1;}
template<typename T>
T ls(T x){return x<<1;}
template<typename T>
T rs(T x){return x<<1|1;}
template<typename T>
T abs_(T a){return a<0?-a:a;}
template<typename T>
T ceil_(T a,T b){return a%b?a/b+1:a/b;}
template<typename T>
T log_(T a,T b){return log(b)/log(a);}
template<typename T>
T gcd(T a,T b){return !b?a:gcd(b,a%b);}
template<typename T>
T lcm(T a,T b){return a/gcd(a,b)*b;}
template<typename T>
void exgcd(T a,T b,T& x,T& y)
{
	if(!b){x=1;y=0;return;}
	exgcd(b,a%b,x,y);
	T temp=x;x=y;
	y=temp-a/b*y;
}
template<typename T>
T solve_function(T a,T b,T c)
{
	if(a<0){a=-a;c=-c;}
	T x,y,base=gcd(a,b);
	exgcd(a,b,x,y);
	x*=c/base;T p=b/base;
	x=(x%p+p)%p;
	if(x<0) x+=abs_(p);
	return x;
}
template<typename T>
T reverse_element(T a,T k){return solve_function(a,k,(T)1);}
template<typename T>
T slow_multi(T a,T b,T p)
{
	T ret=0;
	while(b)
	{
		if(b&1) ret=(ret+a)%p;
		a=(a<<1)%p;
		b>>=1;
	}
	return ret;
}
template<typename T>
T qpow(T a,T b)
{
	T ret=1,base=a;
	while(b)
	{
		if(b&1) ret=ret*base;
		base=base*base;
		b>>=1;
	}
	return ret;
}

int read()
{
	int ret=0,base=1;
	char ch=getchar();
	while(!isdigit(ch))
	{
		if(ch=='-') base=-1;
		ch=getchar();
	}
	while(isdigit(ch))
	{
		ret=(ret<<1)+(ret<<3)+ch-48;
		ch=getchar();
	}
	return ret*base;
}

struct way
{
	int to,next;
}edge[200005];
int cnt2,head[100005];

void add(int u,int v)
{
	edge[++cnt2].to=v;
	edge[cnt2].next=head[u];
	head[u]=cnt2;
}

void add_(int u,int v){add(u,v);add(v,u);}

int n,color[100005],sum[100005],son[100005];
int maxCnt,tot,cnt[100005],ans[100005];

void dfs1(int u,int fa)
{
	sum[u]=1;
	for(int i=head[u];i;i=edge[i].next)
	{
		int v=edge[i].to;
		if(v==fa) continue;
		dfs1(v,u);
		sum[u]+=sum[v];
		if(sum[v]>sum[son[u]]) son[u]=v;
	}
}

void get_light_son(int u,int hson,int fa,int k)//统计轻儿子
{
	cnt[color[u]]+=k;
	if(k>0&&cnt[color[u]]==1) tot++;
	if(k<0&&cnt[color[u]]==0) tot--;
	for(int i=head[u];i;i=edge[i].next)
	{
		int v=edge[i].to;
		if((k==1&&v==hson)||v==fa) continue;
		get_light_son(v,hson,u,k);
	}
}

void dfs(int u,int fa)
{
	for(int i=head[u];i;i=edge[i].next)
	{
		int v=edge[i].to;
		if(v!=fa&&v!=son[u]) dfs(v,u); 
	}
	if(son[u]) dfs(son[u],u);
	get_light_son(u,son[u],fa,1);
	ans[u]=tot;
	if(u!=son[fa]) get_light_son(u,son[u],fa,-1);
}

int main()
{
	n=read();
	for(int i=1;i<n;i++) add_(read(),read());
	for(int i=1;i<=n;i++) color[i]=read();
	dfs1(1,0);dfs(1,0);
	for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
 	return 0;
}

启发式合并、树上启发式合并(基础) 启发式合并 阅读详情

相关推荐

STM32F407硬件IIC驱动OLED避坑实录:从‘不显示’到‘稳定刷屏’的完整调试过程

本文详细记录了使用STM32F407硬件IIC驱动OLED屏幕的完整调试过程,从初始的‘不显示’问题到最终实现‘稳定刷屏’。文章涵盖了硬件接线、I2C外设配置、常见问题排查及性能优化技巧,特别针对STM32标准库开发中的难点提供了实用解决方案,是嵌入式开发者驱动OLED屏幕的实用指南。

weixin_30315723的博客 303

树上启发式合并/dsu on tree的简单应用

dsu on tree,树上启发式合并,轻重链剖分,树上数颜色,CF600E,赛氪2021冬季赛,树的果实,CF1709E

深海鱼!的博客 324

精益六西格玛Python数字化应用开发-Day18 应用场景:家电企业生产效率优化

本文将重点介绍专门针对精益六西格玛黑带使用场景的 Python 库,这些库功能侧重于数据分析和流程优化,特别适用于 DMAIC 方法论和看板管理。考虑到读者具备中高级Python 使用经验,我们将深入探讨各库的高级功能和实际应用应用场景。 某家电企业生产线自动化程度高,数据量巨大,希望通过精益管理提升生产效率。企业借助 Python 脚本,打通各类数据源(MES、ERP、设备日志),自动归集生产数据,分析各工序的生产节拍、设备停机、效率损失,快速定位瓶颈环节

m0_56592100的博客 905

启发式合并

我觉得启发式合并真的很需要策略,巨大的思维量。启发式合并,就是用并查集合并两个节点时,根据节点携带信息的大小siz,来决定合并方向。从而使得合并时遍历节点信息的复杂度稳定在Onlogn左右。一般启发式合并的难点还是在于那个并查集指代的信息,要维护节点的什么信息,合并时是否要将信息拎出来计算答案等……总之很有思维量,会很难调,但是时间复杂度很优秀。

m0_60506105的博客 974

CODESYS V3.5 SP17编程环境全攻略:从安装到多语言编程实战

本文全面解析CODESYS V3.5 SP17编程环境,从安装配置到多语言编程实战技巧。详细介绍了运行时环境设置、六种IEC 61131-3语言的特性对比与混合编程策略,以及高级功能开发如自定义算法模块和实时通信配置。适合工业自动化工程师快速掌握这一强大工具。

weixin_30632089的博客 489

THB6128步进电机驱动芯片介绍

THB6128芯片也称为步进电机驱动芯片,采用BiCDMOS工艺,IC管脚间距为1mm的小型MFP30KR封装而成。

weichen_78的博客 7182

【Luogu U41492】树上数颜色——树上启发式合并(dsu on tree)

(这题在洛谷主站居然搜不到……还是在百度上偶然看到的) 题目描述 给一棵根为1的树,每次询问子树颜色种类数 输入输出格式 输入格式: 第一行一个整数n,表示树的结点数 接下来n-1行,每行一条边 接下来一行n个数,表示每个结点的颜色c[i] 接下来一个数m,表示询问数 接下来m行表示询问的子树 输出格式: 对于每个询问,输出该子树颜色数 说明 对于前三组数据,1...

weixin_30274627的博客 636

从零到一:OptimizePI Pre-layout PDN前仿真实战指南

本文详细介绍了如何使用OptimizePI进行电源完整性(PDN)前仿真,从软件安装配置到元器件建模、去耦电容配置及仿真参数设置,提供了实战技巧和常见问题排查指南。通过OptimizePI的Pre-layout仿真,工程师可以在PCB布局前优化电源分配网络,显著提升设计效率并降低成本。

weixin_28304023的博客 506

树上启发式合并总结

前言 某一天发现一道树上启发式合并裸题,但我不会写…… 学习并刷了两天的题,是时候来写个总结了 正文 树上启发式合并(DSU on Tree),是一个在O(nlogn)O(nlogn)O(nlogn)时间内解决许多树上问题的有力算法。 但它的中心其实是——暴力! 没错,它正是由暴力优化而来。 我们先看一道例题:CF600E Lomsat gelral 题意简述:一棵树有n个结点,每个结点都是一种颜...

p_b_p_b的博客 6242

亚马逊SP-API授权实战:从OAuth流程到Refresh Token获取

本文详细解析了亚马逊SP-API授权流程,从OAuth认证到Refresh Token获取的全过程。通过实战经验分享,帮助开发者快速掌握Marketplace Appstore、Website Workflow和自行授权三种方式,解决常见错误如MD5100和MD9999,并提供了安全存储Refresh Token的最佳实践。

weixin_30379531的博客 518

Mmdetection用自己的数据集训练Mask_RCNN

将自己数据的标签写入配置文件,在data前一行添加自己的标签列表,同时在train,val,test中添加classes = classes,如果不添加,模型就会默认读取coco原始数据集的80个标签,与自己的数据集对应不上就会报错。2.打开第二个文件coco_instance.py,将data_root路径改为你自己coco数据集的位置(注意一定要以/结尾),修改输出图片尺寸(根据自己的数据集决定)3.将标注完的数据转为Mask_rcnn训练所需的数据集格式。4.将数据集放到训练代码文件夹中。

m0_64298393的博客 3472

洛谷U41492(树上启发式合并)

提交通道 洛谷日报 考虑非\(O(n^2)\)的预处理。一遍dfs时,check某颜色有没有的数组何时清空很尴尬:得到某树答案后如果不清,则影响接下来兄弟树的搜索;如果清了,父亲节点又难以收集答案。 解决方法:先让儿子们各顾各的家,算一遍各自的答案(假如能算),check清就清了吧。然后考虑人为优化,即重链求完后等一等!先别清!然后将轻链重新扫一遍,也不清check数组的。代码中的kee...

278

如何使用ArcGIS Pro制作带基底三维地图

点击运行生成范围线,因为之前对高程进行了夸大,导致生成的范围线和地形边缘不重合,我们打开范围线的图层属性,选择高程选项卡,要素位于选择地面上,如下图所示。目前制作的三维地图下面是空的一片,现在添加一个基底,在工具箱内点击“3D Analyst工具\栅格\转换\栅格范围”,调用栅格范围工具,如下图所示。打开ArcGIS Pro,新建一个局部场景,在高程表面下,地面上点击右键,选择添加高程源图层,将需要制作三维地图的DEM数据加载进来,如下图所示。在要素图层菜单内,类型选择绝对高度,如下图所示。

3978

树上启发式合并

这只是人们的基于直觉,一般来说树越大往往越高,那么小树优先合并到大树上面,似乎可以使得树高较低一点,是一种启发式策略,所以称为。暴力思路:对每一个子节点进行一次遍历,每次遍历是O(N)的,因此总体时间复杂度O(N^2)处理完所有的轻儿子之后,对于重儿子我们根据欧拉序,累加整棵子树的颜色——O(N),并且保留。外,还有类似于树链剖分的做法,我们也做 轻重儿子 的划分,这样做事实上有很优秀的性质。轻儿子dfs计算答案,即dfs轻儿子后,轻儿子子树内的贡献不保存在 cnt[] 数组。轻儿子:除了重儿子之外的。

EQUINOX1的博客 852

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

U41492 数颜色 树上启发式合并

树上启发式合并的经典问题。 首先离线处理答案。用一个颜色数组记录某种颜色是否存在过,然后由于不同子树统计答案的时候互不影响,我们枚举子树的时候要清空之前的数组,但是这就带来了一个问题,我们无法向上合并答案了。 启发式合并的做法是我们先考虑树剖预处理,然后对于统计一个结点的答案,先暴力递归所有轻儿子的答案不保留数组,然后递归重儿子并且保留数组,然后再次递归所有的轻儿子这次也保留数组,从而向上更新答案...

qq_40859782的博客 212

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

U41492 树上数颜色(dsu)

U41492 树上数颜色 题意: 输入n(1e5)n(1e5)n(1e5)表示一棵根为1的树有nnn个节点 接下来n−1n-1n−1行每行u,vu,vu,v表示树边 接下来一行nnn个数,c1,c2,…,cn(1≤ci≤n)c_1,c_2,\dots,c_n(1\leq c_i\leq n)c1​,c2​,…,cn​(1≤ci​≤n)表示节点颜色 接下来m(m≤n)m(m\leq n)m(m≤n)...

IQ^QI的博客 477

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

【题目整理】树上启发式合并dsu on tree

真是可爱啊〜 ——《辉夜大小姐想让我告白》四宫辉夜

xhyu61的博客 259

【算法讲20:Dsu on Tree】树上数颜色 | Lomsat gelral

【算法讲20:Dsu on Tree】【例一:树上数颜色】· 暴力做法 ·· 考虑优化 ·⌈Dsu on Tree⌋\lceil Dsu\ on\ Tree\rfloor⌈Dsu on Tree⌋【代码】【例二:Lomsat gelralLomsat\ gelralLomsat gelral】 【例一:树上数颜色】 【链接】 树上数颜色 | 洛谷 U41492 【题意】 给定一棵有根树,有 nnn 个节点,每个节点有一个颜色 cic_ici​

溢流眼泪的博客 961

洛谷U41492 树上数颜色【dsu on tree】

dsu on tree

juruo_c的博客 553

20251208树上启发式合并总结

树上启发式合并在处理离线问题时,其效率往往优于或等同于其他算法,同时具备更容易理解和实现的优势。传统解决方案通常依赖复杂的数据结构,但对于可离线处理的问题,是否存在更简便的方法?,即对每个子节点执行一次遍历(每次遍历复杂度与n同阶),n个节点导致总复杂度为。注意到每个节点的答案可由其子树及自身信息推导得出,这一特性可用于优化处理。启发式合并算法通过将高度较小的树作为高度较大树的子树进行优化。离线处理的核心在于通过预处理实现。直接暴力预处理的时间复杂度为。时间复杂度的查询输出。

scx20131004的博客 247

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

不妨这样做: 每往上传递子树的贡献时, 其他 ( 轻子树 )的仍旧暴力枚举所有点来计算贡献. 最大的那个子树 ( 重子树) 留到最后一个跑 dfs, 此时跑出来的结果不再动他, 直接往上回溯, 就传承给了上一级. 形象地说, 就是所有轻子树合并到了重子树上, 作为 fa 的子树的贡献.就是说: 遍历所有子树的贡献时, 由于换一根子树 dfs 之前就要清除之前子树的贡献, 我们可以选择一个子树作为最后跑 dfs 的, 这样他就是不用清除的, 就可以节省复杂度.可以证明这样的复杂度是。

taulee01 的博客 534

树上启发式合并 学习记录

树上启发式合并

bawangtianzun的博客 255

U41492 dsu on tree

题意 传送门 U41492 树上数颜色 题解 预处理各子树的答案,朴素的方法即对每个节点向下 DFSDFSDFS 一次,时间复杂度 O(N2)O(N^2)O(N2)。考虑到节点的答案为子树信息的叠加,使用树上启发式合并算法。 基本思想是递归求解儿子的答案,将重儿子(即节点数最多的儿子)放到最后求解,且不清空它所记录的信息,此时可以保留的信息是最多的;那么求解当前节点的答案时,只需要再统计一次非重儿子的信息。 定义连向重儿子的为重边,其余为轻边。由于轻边连接的子树节点个数不超过父节点所在子树的节点个数的一半,

neweryyy的博客 173

luogu U41492 树上数颜色 (dsu on tree 或 主席树+dfn序)

这种题还考的挺多的(口胡),我稍微总结了一下,不多,就两个题目 其中一个就是luogu U41492 树上数颜色 另外一个是东北四省E题算是这题的加强版 此处提供两种算法:1.启发式合并 2.主席树 关于启发式合并,大家可以看看这片博客https://www.luogu.org/blog/codesonic/dsu-on-tree 代码略微相似: #include&lt...

weixin_43824564的博客 932

树上启发式合并 待补

对于每个子树,直接遍历所有轻儿子,继承重儿子。会了板子后,修改维护的东西和莫队是一样的。板子,改一下修改操作就行了。

qq_41418557的博客 335

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

题目 题目 题意: T1:给定一棵n个点的树,求每个点以它为树根的子树的颜色种类。 T2:给定一棵n个点的树,求每个点以它为树根的子树的dominating color之和。 dominating color: 在本棵树中出现次数最多(或之一) 思路: dsu on tree,树上启发式合并,不过这个算法并没有用到dsu(并查集)。 考虑暴力求解,以每个点为起点dfs搜索一次,时间复杂度为n^2。 但是可以利用轻重链的性质,优化为nlogn。   注意到一个点的贡献是所有儿子求和,求完和儿子的贡献就用不到了

xianqiuyigedao的博客 349
上一篇: Codeforces 1696D Permutation Graph
下一篇: Codeforces 707E 二维树状数组
stdforces
博客等级 码龄4年 9粉丝 136原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值