启发式合并详解 (基于CF 1620E - Replace the Numbers)

news/2024/11/1 18:32:57/

前言:
这是Educational Codeforces Round 119 (Rated for Div. 2)的第五题,
这个题我最开始使用从后往前的方法写的,复杂度 O ( n ) O(n) O(n)
交完以后我看看了题解,题解提供了两种办法,第二种是用启发式合并(英文名叫 small to large method),看到这我别提有多激动了,因为自从学了启发式合并以后一直没有找到适合练手的题目。
那我就通过这个题来好好梳理一下启发式合并吧。

例题题面
You have an array of integers (initially empty).

You have to perform q queries. Each query is of one of two types:

“1 x” — add the element x to the end of the array;
“2 x y” — replace all occurrences of x in the array with y.
Find the resulting array after performing all the queries.

Input
The first line contains a single integer q (1≤q≤5⋅105) — the number of queries.

Next q lines contain queries (one per line). Each query is of one of two types:

“1 x” (1≤x≤5⋅105);
“2 x y” (1≤x,y≤5⋅105).
It’s guaranteed that there is at least one query of the first type.

Output
In a single line, print k integers — the resulting array after performing all the queries, where k is the number of queries of the first type.

啥是启发式合并
启发式合并,就是高效的、从小到大的合并。它给人的直接感觉很弱,不像线段树什么的能让你瞬间体会到算法的精妙性。实际上,启发式合并可以将很多 n 2 n^2 n2的复杂度降级为 n l o g n nlogn nlogn,如果敏锐地洞察出一个题可以启发式合并,我们的算法性能将得到极大的提升。

启发式合并怎么做
以此题为例,我们为每个数开一个线性表(最好用vector)。执行操作 1 1 1时,若x是第n个追加的元素,则将n放入第 x x x个线性表(也就是说一个线性表里面装了这个值出现的所有位置)。执行操作 2 2 2时,我们要将x出现的位置改为 y y y,也就是要把第 x x x个线性表全部倒入第 y y y个线性表。如果暴力来处理的话,必定会超时。那么怎么优化呢?这里无非是对两个线性表的一个合并,我们利用启发式合并的策略,将较小的那个线性表倒入较大的线性表即可(此处的大小指元素个数)。合并完之后,如果表名不一致颠到,交换一下即可(vector的交换机制是改指针,所以复杂度是 O ( 1 ) O(1) O1的)。需要注意的是,当 x = y x=y x=y时,应当直接跳过。

启发式合并的复杂度
本算法的主要时间消耗在于合并两个线性表(或者说是集合)。
每次合并操作,我们都将小集合倒入大集合,只有小集合中的元素发生了移动,而且最终集合的大小至少是小集合的两倍。
假设 a a a被移动了 b b b次,也就是说 a a a所在的集合的大小发生了b次倍增(有可能比倍增还大)。所以 n > = 2 b n>=2^b n>=2b,也就是说 b < = l o g n b<=logn b<=logn
因此所有元素移动的总次数是 n l o g n nlogn nlogn
仔细阅读我们发现,在推导这个复杂度的时候,我们分析的是移动次数最多的那个元素的最多移动次数,所以这个算法的效率往往比我们预期的还要快很多。

例题代码

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;vector<int>v[500010];
int a[500010];
signed main(){ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int q,num=0;cin>>q;while(q--){int op,x,y;cin>>op;if(op==1){cin>>x;v[x].push_back(++num);}else{cin>>x>>y;if(x==y) continue;if(v[x].size()>v[y].size()){for(auto i:v[y]){v[x].push_back(i);}v[y].clear();swap(v[x],v[y]);}else{for(auto i:v[x]){v[y].push_back(i); }v[x].clear();}}} for(int i=1;i<=500000;i++){for(auto j:v[i]){a[j]=i;}}for(int i=1;i<=num;i++){cout<<a[i]<<' ';}cout<<endl;return 0;
}

http://www.ppmy.cn/news/132347.html

相关文章

[ZCMU OJ]1620: 全排列 1683: 排列(next_permutation全排列函数的使用)

首先我们先来认识一个函数&#xff1a;全排列函数——next_permutation。这个函数用于全排列问题功能十分强大。与之相对还有一个函数prev_permutation&#xff1b;二者区别在于&#xff1a;前者求的是下一个全排列&#xff0c;而后者求的是上一个全排列&#xff1b;二者在用法…

Weblogic 11g 部署

操作系统&#xff1a;RedHat Enterprise Linux 5 32位 Weblogic版本&#xff1a;wls1035_oepe111172_linux32.bin 安装weblogic 1、修改控制参数 [rootyorkshi ~]# vi/etc/security/limits.conf # /etc/security/limits.conf # #Each line describes a limit for a user inthe …

2g 双核电脑 linux,9208)(奔腾双核E5200/2G/320G)电脑详细技术

处理器型&#xff1a;intel 酷睿2双核 p7350 intel 酷睿2双核 p7450 intel 酷睿2双核 t6600 intel 奔腾双核t4300 intel 奔腾双核 t4400 intel 赛扬双核 t1600 intel 赛扬双核 t3000操作系统&#xff1a;windowsvista home basic dos标配内存&#xff1a;1gb 2gb 硬盘容量&…

台式计算机m.2的参数,联想启天M系列

对 比 Intel Pentium E6600 3.06GHz 500GB 集成显卡 暂无 对 比 Intel Pentium G630 2.7GHz 320GB 独立显卡 暂无 对 比 Intel Celeron 420 1.6G 80GB 集成显卡 暂无 对 比 Intel Core2 Duo E7500 500GB 独立显卡 暂无 对 比 Intel Core i5 4570(3.2GHz/L3 6M) 500GB 独立显卡 …

g30u盘启动 中科曙光1620_曙光I620-G20服务器安装windowsserver2008r2方法

在中科曙光 I620-G20 服务器上安装 Windows 2008 R2 系统步骤 1 、制作启动盘 下载 windows 2008 R2 系统镜像文件。使用 UltraISO (软碟通)工具制作启动盘。 使用启动盘 鼠标右键“以管理员身份运行” UltraISO 图标。 浏览到存放镜像文件的目录&#xff0c;选中该目标文件&am…

IntelLinux显卡驱动安装指南

Intel Linux显卡驱动安装指南 1. 简介 通常情况下&#xff0c;Intel显卡驱动已经被集成在Linux发行包里面了&#xff0c;用户无需单独安装。 这篇指导是为那些自己从头开始编译最新版本驱动的人而写的。当你想订制显卡驱动或者了解更多的时候&#xff0c;这篇文章就会管用…

藏经阁(四)数码管 TM1620芯片手册 解析

文章目录 芯片概述芯片特性芯片管脚定义指令解析时序解析实战应用 芯片概述 TM1620是一种LED&#xff08;发光二极管显示器&#xff09;驱动控制专用IC 芯片特性 显示模式&#xff08;8 段 6 位、9段x 5位、10段 4位&#xff09;辉度调节电路&#xff08;8 级占空比可调&…

8051单片机驱动TM1620任意字符循环显示程序(详细注释版)

8051单片机驱动TM1620任意字符循环显示程序 本人亲写&#xff0c;亲测可用 时序图 /************************************************** 名称&#xff1a;STC51驱动TM1620 4位数码管显示MCU: STC11F06主频&#xff1a;11.0592晶振 *************************************…