首页 > 其他分享 >树上启发式合并(dsu on tree)

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

时间:2023-12-08 14:55:56浏览次数:28  
标签:cnt int siz sum dsu tree son fa 启发式

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

当遇到处理子树询问,并且无修改时。可以考虑树上启发式合并。

算法流程:

  • step1:处理出每个点的 \(siz_x\) 以及重儿子 \(son_x\)。
void dfs(int x, int fa) {
	siz[x] = 1;
	int Maxson = 0;
	for(int i = 0; i < p[x].size(); i++) {
		int y = p[x][i];
		if(y == fa) continue;
		dfs(y, x);
		siz[x] += siz[y]; 
		if(siz[y] > Maxson) {
			Maxson = siz[y];
			son[x] = y;
		}
	}
}
  • step2:进入它的所有轻儿子,并删除贡献。
  • step3:进入它的重儿子,这里不删除贡献。
  • step4:将轻儿子加入贡献。
  • step5:如果需要删除贡献,就删除贡献。
void add(int x, int fa, int val) { //加入/删除贡献
	cnt[a[x]] += val;
	if(cnt[a[x]] > Mx) {
		Mx = cnt[a[x]];
		sum = a[x]; 
	}
	else if(cnt[a[x]] == Mx) {
		sum += a[x];
	}
	for(int i = 0; i < p[x].size(); i++) {
		int y = p[x][i];
		if(y == fa || y == Son) continue;
		add(y, x, val); 
	}
}
void Get(int x, int fa, bool opt) {
	for(int i = 0; i < p[x].size(); i++) {
		int y = p[x][i];
		if(y == fa || y == son[x]) continue;
		Get(y, x, 1);
	}
	if(son[x]) Get(son[x], x, 0), Son = son[x];
	add(x, fa, 1); Son = 0;
	ans[x] = sum;
	if(opt) add(x, fa, -1), sum = 0, Mx = 0;
}

时间复杂度为 \(n \log n\)。

这就是CF600E的代码。

#include<bits/stdc++.h>
#define int long long
#define N 100005
using namespace std;
int n;
int a[N], son[N], siz[N], cnt[N];
vector<int>p[N];
void dfs(int x, int fa) {
	siz[x] = 1;
	int Maxson = 0;
	for(int i = 0; i < p[x].size(); i++) {
		int y = p[x][i];
		if(y == fa) continue;
		dfs(y, x);
		siz[x] += siz[y]; 
		if(siz[y] > Maxson) {
			Maxson = siz[y];
			son[x] = y;
		}
	}
}
int Son = 0, sum = 0, Mx = 0;
int ans[N];
void add(int x, int fa, int val) {
	cnt[a[x]] += val;
	if(cnt[a[x]] > Mx) {
		Mx = cnt[a[x]];
		sum = a[x]; 
	}
	else if(cnt[a[x]] == Mx) {
		sum += a[x];
	}
	for(int i = 0; i < p[x].size(); i++) {
		int y = p[x][i];
		if(y == fa || y == Son) continue;
		add(y, x, val); 
	}
}
void Get(int x, int fa, bool opt) {
	for(int i = 0; i < p[x].size(); i++) {
		int y = p[x][i];
		if(y == fa || y == son[x]) continue;
		Get(y, x, 1);
	}
	if(son[x]) Get(son[x], x, 0), Son = son[x];
	add(x, fa, 1); Son = 0;
	ans[x] = sum;
	if(opt) add(x, fa, -1), sum = 0, Mx = 0;
}
signed main() {
    scanf("%lld", &n);
    for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
    for(int i = 1, u, v; i <= n - 1; i++) {
    	scanf("%lld %lld", &u, &v);
    	p[u].push_back(v);
		p[v].push_back(u); 
	} 
	dfs(1, 0);
	Get(1, 0, 0);
	for(int i = 1; i <= n; i++) {
		printf("%lld ", ans[i]);
	}
	return 0;
}

后面是一些我做过的简单题:

CF375D

CF208E

CF1009F

CF246E

标签:cnt,int,siz,sum,dsu,tree,son,fa,启发式
From: https://www.cnblogs.com/xcs123/p/17887159.html

相关文章

  • Sourcetree安装详细步骤
    Sourxetree作为免费的Git客户端工具,有许多优点。Sourcetree简化了与Git存储库交互的方式,因此我们可以专注于编码。通过Sourcetree简单又快捷的管理我们的存储库。1.下载https://www.sourcetreeapp.com/2.安装3.创建伪账号进入文件夹%LocalAppData%\Atlassian\Source......
  • 打工笔记----------------------------跨进程控制SysTreeView32树状图控件的问题
    跨进程控制SysTreeView32树状图控件的问题,啥也不说了,直接上代码:publicpartialclassForm1:Form{//定义常量publicconstintWM_LBUTTONDBLCLK=0x020B;//左键双击消息publicconstintWM_RBUTTONDOWN=0x0204;//右键按下消息......
  • [ARC121F] Logical Operations on Tree 题解
    题目链接点击打开链接题目解法比较好的题首先要发现一个性质是:先删AND边,再删OR边最优小证一下:分类讨论AND边两端的数字情况\(0\&0\)左右两端虽然可能可以把\(1\)OR过来,但这种情况先做\(\&\),也一定可以OR得到\(1\)\(0\&1\)左边可能可以\(OR\)得到\(1......
  • 【题解】CodeForces 1902F Trees and XOR Queries Again
    传送门:https://codeforces.com/contest/1902/problem/F数据结构题,这里讲两种思路。$ST$表思路:判定“从若干个数中能否取出其中一些,使得异或和为$x$”的问题,第一时间想到线性基,本题要做的显然就是快速求出询问路径上所有数的线性基。两组数的线性基可以合并,方法为“暴力将......
  • QuadTree 优化版
     QuadTree.h#pragmaonce#include<iostream>#include<string>#include<stdlib.h>#include<ctime>#include<vector>#include<algorithm>usingnamespacestd;#defineMAX_ELE_NUM300//每块区域的最大点数#defineQUADRANT_R......
  • F. Trees and XOR Queries Again
    首先容易想到lca+线性基,\(O(nlognB^2+qlognB^2)\),显然T飞了。#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#include<map>#include<vector>#include<set>#include<iostream>#include<queue>#i......
  • binarySortTree
    二叉排序树二叉排序树BST(BinarySot(Search)Tree):对于二又排序树的任何一个非叶子节点,要求左子节点的值比当前节点的值小,右子节点的值比当前节点的值大。算法描述:第一种情况:删除叶子节点(比如:2,5,9,12)思路:(1)需求先去找到要删除的结点targetNode(2)找到targetNode......
  • 【刷题笔记】124. Binary Tree Maximum Path Sum
    题目Givena non-empty binarytree,findthemaximumpathsum.Forthisproblem,apathisdefinedasanysequenceofnodesfromsomestartingnodetoanynodeinthetreealongtheparent-childconnections.Thepathmustcontain atleastonenode anddoes......
  • Top Tree 模板(咕)
    Sone1调不动了,所以是lgP3690。写着写着就不知道自己写的是AAAT还是SATT了,反正能用。#include<iostream>#include<vector>#include<cassert>#defineUP(i,s,e)for(autoi=s;i<e;++i)usingstd::cin;usingstd::cout;constexprintN=1e5,M=3e5;namespac......
  • 处理XML--xml.etree.ElementTree
    XML文档的根元素根元素是XML文档中所有其他元素的父元素。它是文档的起点,必须是唯一的<root><!--其他元素和内容--></root>介绍xml信息属性类型意义调用tagstrElement名Element.tagattribdic元素有哪些属性Element.attribtextstr第一个子......