ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

学习笔记——启发式合并

2021-06-27 18:04:59  阅读:167  来源: 互联网

标签:int ed 合并 笔记 fa ans 启发式 include


我们要把N个集合,总共M个元素合并成一个大集合。

很容易得出,最坏的情况下需要合并N次,每次合并M个元素,也就是O(MN)的时间复杂度。

同样的问题,如果我们把小的往大的里合,是不是就快很多?

那么他的复杂度是多少呢?

考虑一个集合,被合并一次后他的大小至少乘2,那么他被合并的次数至多为\(logn\)次,对于集合内的每一个元素至多会合并\(logn\)次,那么总共会合并\(O(nlogn)\)

例题:loj dp一般看规律

对于将一个元素换成另一种颜色的操作,不难抽象成把两个元素合并,这样最多会进行\(logn\)次有效操作

启发式合并代码:

void merge(int x,int y){
//	cout<<"x = "<<x<<" "<<y<<endl;
	bool flag = 0;
	if (s[x].size() > s[y].size()) swap(x,y),flag = 1;
	for (auto i = s[x].begin();i != s[x].end();i++){
		auto lst = s[y].lower_bound(*i);
		if (lst != s[y].end()) ans = min(ans,*lst-*i);
		auto pre = s[y].lower_bound(*i);
		if (pre != s[y].begin()) pre--,ans = min(ans,*i-*pre);
	}
//	cout<<"size = "<<s[x].size()<<" "<<s[y].size()<<endl;
	for(auto i = s[x].begin();i != s[x].end();i++) s[y].insert(*i);
	s[x].clear();
	if (flag) swap(s[x],s[y]); 
}

约定x比y小,然后把x合并到y上,然后把小的清空,最终保证y是合并后的集合

例题2:CF600E Lomsat gelral

这道题我们可以遍历整棵树,并记录每种颜色出现几次

但是每做完一棵子树就需要清空,以免对其兄弟造成影响。

而这样做它的祖先时就要把它重新搜一遍,浪费时间

但是我们发现,对于每个节点v,最后一棵子树是不用清空的,因为做完那棵子树后可 以把其结果直接加入v的答案中。

选哪棵子树呢?当然是所含节点最多的一棵咯,我们称之为“重儿子”

考虑一个点会被计算几次,他可以分为两个部分,dfs和暴力统计答案

对于前者每个点只会被经过1次,对于后者,因为从一个点向上跳最多有log个轻边,所以会被经过\(logn\)次,这样n个点复杂度为\(nlogn\)

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
#define int long long
#define B cout<<"Breakpoint"<<endl;
#define O(x) cout<<#x<<" "<<x<<endl;
#define o(x) cout<<#x<<" "<<x<<" ";
using namespace std;
int read(){
	int x = 1,a = 0;char ch = getchar();
	while (ch < '0'||ch > '9'){if (ch == '-') x = -1;ch = getchar();}
	while (ch >= '0'&&ch <= '9'){a = a*10+ch-'0';ch = getchar();}
	return x*a;
}
const int maxn = 1e5+10;
int n,col[maxn];
struct node{
	int to,nxt;
}ed[maxn << 1];
int head[maxn],tot;
int sum,maxx;
void add(int u,int to){
	ed[++tot].to = to;
	ed[tot].nxt = head[u];
	head[u] = tot;
}
int siz[maxn],son[maxn];
void dfs_init(int x,int fa){
	siz[x] = 1;
	for (int i = head[x];i;i = ed[i].nxt){
		int to = ed[i].to;
		if (to == fa) continue;
		dfs_init(to,x);
		siz[x] += siz[to];
		if (siz[son[x]] < siz[to]) son[x] = to; 
	}
}	
int c[maxn],ans[maxn];
void getans(int x,int fa,int pos){
	c[col[x]]++;
	if (c[col[x]] > maxx) maxx = c[col[x]],sum = col[x];
	else if (c[col[x]] == maxx) sum += col[x];
	for (int i = head[x];i;i = ed[i].nxt){
		int to = ed[i].to;
		if (to == fa||to == pos) continue;
		getans(to,x,pos);
	}
}	
void clear(int x,int fa){
	c[col[x]]--;
	for (int i = head[x];i;i = ed[i].nxt){
		int to = ed[i].to;
		if (to == fa) continue;
		clear(to,x);
	}
}
void dfs(int x,int fa){
	for (int i = head[x];i;i = ed[i].nxt){
		int to = ed[i].to;
		if (to == fa||to == son[x]) continue;
		dfs(to,x),clear(to,x),sum = maxx = 0;
	}
	if (son[x]) dfs(son[x],x);
	getans(x,fa,son[x]);
	ans[x] = sum;
}
signed main(){
	n = read();
	for (int i = 1;i <= n;i++) col[i] = read();
	for (int i = 1;i < n;i++){
		int x = read(),y = read();
		add(x,y),add(y,x);
	}
	dfs_init(1,0);dfs(1,0);
	for (int i = 1;i <= n;i++) printf("%lld ",ans[i]);
	return 0;
}

标签:int,ed,合并,笔记,fa,ans,启发式,include
来源: https://www.cnblogs.com/little-uu/p/14941460.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有