【NOIP2014模拟10.30】二叉查找树(顺便记录一下迭代器)

这篇博客主要介绍了如何使用二叉查找树解决NOIP2014模拟赛中的问题,涉及到树的插入操作和计数器的更新。同时,文章探讨了迭代器的概念,包括在解决此类问题中如何利用迭代器进行高效操作,如set中的lower_bound函数。内容涵盖二叉查找树的性质、插入算法以及迭代器的初步应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【NOIP2014模拟10.30】二叉查找树

Description

二叉查找树是二叉树,每个结点最多只有两个孩子结点。每个结点都有一个整数权值val。如果某个结点的权值是X,那么她的左子树的结点权值都小于X,右子树的结点权值都大于X。
现在要通过依次插入N个整数构造出二叉查找树,每个整数范围【1,N】,且都不相同,即要插入的序列是一个排列。第一个被插入的整数作为树根结点root,接下来依次插入剩下的N-1个整数,每次插入一个整数就相当于执行函数:insert(X, root),其中insert(X, root)递归过程如下:

insert( number X, node now )
{
计数器C 加1
if 待插入的整数X小于结点now的权值 then

if 结点now无左孩子 then
新建一个权值为X的结点,并设置为now的左孩子
else insert(X, now的左孩子)

else

if 结点now无右孩子 then
新建一个权值为X的结点,并设置为now的右孩子
else insert(X, now的右孩子)
}
}
其中:计数器C是全局变量,初始值是0。

Input

第一行,一个整数 N (1 ≤ N ≤ 300000)。
接下来有N行,每行一个整数,每个整数的范围是[1, N],且所有待插入的整数都不相同。

Output

共N行,每行以一个整数,第i行输出的结果表示的意义是:把第i个整数插入到查找二叉树后,计数器C的值是多少。

Sample Input

输入1:
4
1
2
3
4
输入2:
5
3
2
4
1
5
输入3:
8
3
5
1
6
8
7
2
4

Sample Output

输出1:
0
1
3
6
输出2:
0
1
2
4
6
输出3:
0
1
2
4
7
11
13
15

题目大意

建一个二分查找树,每一次插入新的元素时,输出在这之前所有的深度(也就是ans+=d[i])

思路

显然按照题目描述打50分肯定是有的哩,之后呢我们就会发现,一个数它的深度应该是它爸爸的深度+1(废话),但是它的爸爸呢很显然,要不是比它大的数中最小的数(前驱),就是比它小的数中最大的数(后继)。结果呢就可以得到d[i]=max(d[前驱],d[后继])+1。

那么就比较轻松 ,这个呢用双向链表,线段树都是可以的,但是呢,双向链表不会,线段树也只会简单的,结果导致这个半个月前的 题,拖到现在。忍无可忍,无需再忍!“好像可以搞平衡树哦”,“平衡树?学学”,结果。。。懂了是懂了,但是他们的那个代码,真心自闭啊。“set不就是用红黑树的嘛”,“对哟,set!”,结果一整天都在学指针和迭代器,心里苦。

不过好歹会了嘛,起码会用了什么lower_bound之类的。

还是说两嘴迭代器吧。

迭代器

迭代器是今天才正式涉及的,说的不精准还请见谅,大概嘛,跟指针差不多,就我的理解,应该是储存一个数的地址,那要它干什么呢,比如像等会用的set,里面的lower_bound(x)就是指在集合里找到>=x的最小的数的迭代器,(啊,好绕啊,就是地址,我就是这么理解的),好了像定义之类的等会到程序里再说。

上代码

#include<cstdio>
#include<iostream>
#include<set>
#define N 300007
using namespace std;
long long n,ans,d[N],a[N];//保险起见longlong,d为深度
int main(){
	scanf("%lld",&n);
	scanf("%lld",&a[1]);//先将第一个数输进来,方便点
	printf("0\n");//第一个输出必定是0
	set<long long>A;
	A.insert(a[1]);//将a[1]放进集合
	d[a[1]]=0;//注意是a[1]这个值的深度,不是1的深度。
	for(int i=2;i<=n;i++){
		scanf("%lld",&a[i]);
		set<long long>::iterator A1,A2;//好了这里就是定义一个迭代器了,类型::iterator 变量名
		A1=A.lower_bound(a[i]);//跟上面说的一样
		A2=A1;//这个时候它们都是后继(如果a[i]有后继的话)
		if(A1!=A.begin()) A1--;
		if(A2==A.end()) A2--;
		//A1为前驱,A2为后继。若A1为第一个数的地址的话,那么说明没有前驱,若A2为end(),说明没有找到,也就是没有后继
		d[a[i]]=max(d[*A2],d[*A1])+1;//疑问为什么有*号,因为A1,A2是迭代器,是地址,要想调用地址上的值,就要加上*
		ans+=d[a[i]];
		printf("%lld\n",ans);
		A.insert(a[i]);//一定放下面,因为迭代器会自动更新的
	}
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值