代码编织梦想

dsu on tree

BB

dsu on tree 树上并查集?
其实这东西跟并查集一点关系都没有吧(可能是我太年轻
树上启发式合并 和莫队一样有着 看上去 貌似 特别 高深 的名字,其实就是XJB暴力

正题
实质上dsu on tree运用了一个轻重链剖分的思想。
适用于不带修改的树上询问操作 离线操作 比莫队优越

有些树上题目我们每次暴力时间复杂度是 O ( n 2 ) \mathcal{O(n^2)} O(n2)的,而dsu on tree的复杂度是 O ( n l o g n ) \mathcal{O(nlogn)} O(nlogn)

对于每个树上每个节点
它的答案是从它的子节点更新上来的 但是有因为我们的空间不允许 所以不能把所有点的所有信息保存下来
但是我们能发现在同一个节点下的子节点是互不干涉的
所以就可以共用了啊
但是每次都要保留一个最重的儿子来减少操作次数
我们先统计一个节点所有的轻儿子 然后删除它的答案
再统计这个节点的重儿子 保留他的答案
最后为了上传信息 再算一遍所有轻儿子 加到答案中就可以了

∵ T ( n ) = 2 T ( n / 2 ) + O ( n ) \because T(n)=2T(n/2)+O(n) T(n)=2T(n/2)+O(n)
∴ T ( n ) = O ( n l o g n ) \therefore T(n)=O(nlogn) T(n)=O(nlogn)
(这应该学过一点数学的都会叭)
例题(dsu on tree 入门经典题)
Codeforces600E. Lomsat gelral
就是维护当前节点下的最多的颜色,就是模板了叭

#include <cstdio>
#include <cstring>
#include <iostream>
#define N 100010

using namespace std;
typedef long long LL;
struct Node{
	int to, nxt;
}e[N << 1];

LL sum, ans[N];
int size[N], ss[N], lst[N], cnt, tot[N], c[N], maxx, skip[N];

inline void add(int u, int v) {
	e[++cnt].to = v;
	e[cnt].nxt = lst[u];
	lst[u] = cnt;
}

inline void dfs(int x, int fa) {
	size[x] = 1;
	for (int i = lst[x]; i; i = e[i].nxt) {
		int son = e[i].to;
		if (son == fa) continue;
		dfs(son, x);
		size[x] += size[son];
		if (!ss[x] || size[son] > size[ss[x]]) ss[x] = son;
	}
}

inline void count(int x, int fa, int k) {
	tot[c[x]] += k;
	if (k > 0 && tot[c[x]] > maxx) {
		maxx = tot[c[x]];
		sum = c[x];
	}
	else if (k > 0 && tot[c[x]] == maxx) sum += c[x];
	for (int i = lst[x]; i; i = e[i].nxt) {
		int son = e[i].to;
		if (son == fa || skip[son]) continue;
		count(son, x, k);
	}
}

inline void makeans(int x, int fa, int kep) {
	for (int i = lst[x]; i; i = e[i].nxt) {
		int son = e[i].to;
		if (son == fa || son == ss[x]) continue;
		makeans(son, x, 0);
	}
	if (ss[x]) makeans(ss[x], x, 1), skip[ss[x]] = 1;
	count(x, fa, 1);
	ans[x] = sum;
	if (ss[x]) skip[ss[x]] = 0;
	if (!kep) count(x, fa, -1), maxx = sum = 0;
}

int main() {
	int n;
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i) {
		scanf("%d", &c[i]);
	}
	for (int i = 1, x, y; i < n; ++i) {
		scanf("%d%d", &x, &y);
		add(x, y);
		add(y, x);
	}
	dfs(1, 1);
	makeans(1, 1, 1);
	for (int i = 1; i < n; ++i) {
		cout << ans[i] << " ";
	}
	cout << ans[n];
	return 0;
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/jokingcoder/article/details/89092819

dsu on the tree 学习笔记-爱代码爱编程

dsu貌似就是启发式合并的意思,大家都知道这个东西是很神奇的,把n^2级别的复杂度降到nlogn,特别厉害的。 考虑如下问题:一棵树,问以每个点为根的子树中,和它颜色相同的有多少个节点(n<=10w,颜色数因为可以离

dsu on tree——令人惊叹的想法_xsamsara的博客-爱代码爱编程

DSU on tree 首先感谢LX dalao的讲解。 DSU on tree用于解决静态树上众数问题,比如说Codeforces 600E 题目大意 给你一棵树,每个节点有一种颜色,问你每个子树x的颜色数最

dsu_on_tree_半世blue的博客-爱代码爱编程

大佬博客:https://codeforces.com/blog/entry/44351 使用范围:常用来求子树的信息,比如,如果一棵树上每个节点都有一种颜色,求一个子树中颜色c的出现次数 复杂度分析:这个就是启发式合并

dsu——树上的文艺的暴力_dancingz的博客-爱代码爱编程

Description 一个有根树,以1为根。多次询问,每次询问u的k级后代有多少个。 Input 第一行两个数N,M表示树的大小和询问个数 之后N-1行每行两个数a b表示a和b之间有一条边 之后M行每行两个数u,k表示一个询问,问u的k级后代有多少个 Output 输出M行,代表每个询问的答案 Sample Input 7 1 2 1

【启发式合并】(dsu on tree)讲解_floraqiu的博客-爱代码爱编程

【启发式合并】(dsu on tree)讲解+例题 超级好的讲解(来自cf) 一、启发式合并的作用: 我们可以在O(nlogn) 的时间内,回答下列形式的所有询问: 节点v的子树中有多少节点有某种特性。 例如:

dsu on tree(树上启发式合并)详解-爱代码爱编程

题外话 据说dsu on tree这个名字十分的离谱,原先它指的是一种代码风格,后来莫名其妙用来指代树上启发式合并这个算法。 以及这个算法和dsu(并查集)更是没有什么关系,这也十分的离谱qwq。 介绍 这是个用来处

( 数据结构专题 )【 dsu on tree】-爱代码爱编程

( 数据结构专题 )【 dsu on tree】 推荐视频:https://www.bilibili.com/video/av71124048?p=2   例题1 :  题意: 一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和。 输入 :  4 1 2 3 4 1 2 2 3 2 4

Lomsat gelral(dsu on tree模板理解)-爱代码爱编程

https://www.luogu.com.cn/problem/CF600E 题意翻译 有一棵 nn 个结点的以 11 号结点为根的有根树。每个结点都有一个颜色,颜色是以编号表示的, ii 号结点的颜色编号为 c_ici​。如果一种颜色在以 xx 为根的子树内出现次数最多,称其在以 xx 为根的子树中占主导地位。显然,同一子树中可能有多种颜色占主导地

Tree(思维+动态开点+dsu on tree)-爱代码爱编程

本来做的是农林的题,那题直接dsu就过了。 https://ac.nowcoder.com/acm/contest/7872/J 原意就是用来练dsu on tree的,牛客数据水不会有mle的问题。   思路:结合前面来说,我们来具体考虑暴力怎么做。 由于题目给出x,y不能互相为lca,这个条件如果直接去实现会比较困难。 转化一下,也就是说考

[dsu on tree]树上启发式合并总结(算法思想及模板附例题练习)-爱代码爱编程

文章目录 前言树上启发式合并引入算法思想时间复杂度模板练习例题:CF600E Lomsat gelralsolutioncodeCF208E Blood CousinssolutioncodeCF570D Tree RequestssolutioncodeCF1009F Dominant Indicessolutioncode 前言 最近不是

dsu on tree(树上启发式合并)-爱代码爱编程

详解:dsu on tree(树上启发式合并)算法总结+习题 经典例题:https://vjudge.net/problem/CodeForces-600E 题意:一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和。 dsu on tree简介: 在O(N^2)的暴力做法中,我们用cnt记录每种颜色出现的次数

【总结】dsu on tree-爱代码爱编程

简介 树上启发式合并简称 dsu on tree ,其思想在于 暴力跑轻儿子的贡献 ,同时用桶记录下 重儿子的贡献 ,可以用于一类树的统计问题或 dp 优化,可以做到时间复杂度 O(nlogn) ,空间复杂度 O(n) 。 引入 直接讲实现方法吧。毕竟其他方法都没有实际意义。 Part 1. 预处理子树大小和重儿子 void dfs(int x,

dsu on tree 模板 (树上启发式合并)-爱代码爱编程

题目题目题意: T1:给定一棵n个点的树,求每个点以它为树根的子树的颜色种类。 T2:给定一棵n个点的树,求每个点以它为树根的子树的dominating color之和。dominating color: 在本棵树中出现次数最多(或之一)思路: dsu on tree,树上启发式合并,不过这个算法并没有用到dsu(并查集)。 考虑暴力求解,以每个点为起点d

dsu on tree模板-爱代码爱编程

dsu on tree解决某个子树的众数,种类数问题  时间复杂度  #include <bits/stdc++.h> using namespace std; const int N=1e5+10; int h[N],to[2*N],ne[2*N],cnt; int sz[N],dep[N],fa[N],son[N]; int

树上启发式合并入门-爱代码爱编程

简述: 树上启发式合并又叫 dsu on tree ,是解决可以离线的子树问题的一种方法。 优点:时间复杂度优秀 O