二叉查找树
时间限制:1 s 内存限制:512 MB
【题目描述】
二叉查找树是一种特殊的二叉树(每个节点最多只有两个儿子的树)。树的每个节点上存有一个唯一的值,并且满足:这个节点的左子树内所有点的值都比这个节点的值小,且右子树内所有点的值都比这个节点的值要大。
对于一棵二叉查找树T,我们可以将一个值为 x的新点插入 T中,且保持树的性质。算法如下:
需要将 x 插入树 T时,执行 insert(x,T.root)。
现在有 N 个数需要插入一棵空树中。给定插入序列,请在每个元素被插入之后,输出所有节点的深度总和(根的深度为 0)。
【输入格式】
输入的第一行一个整数 n,表示序列长度。
接下来一行n个数是序列中的数字,这些数字是各不相同的,在[1, n]区间。
【输出格式】
输出 n 行,第 i 行整数表示第 i个数插入树后,至这个节点的节点深度总和。
【样例输入】
8 3 5 1 6 8 7 2 4
【样例输出】
0 1 2 4 7 11 13 15
【数据规模与约定】
对于 50%的数据,满足n ≤ 1000
对于100%的数据,满足n ≤ 3 ∗ 1e5
【来源】
qbxt 2017.10.7 t1
我们可以发现,这棵二叉搜索树构建完毕之后,根节点总是比他的子树内任意一个节点先插入 ,而直接构造是n^2级别的,我们需要知道有一种东西叫笛卡尔树,其实就是一颗treap,既满足二叉搜索树的性质,又满足堆的性质,对于任意一个节点有两个值,key和fix,key满足二叉搜索树,fix满足堆,如果key是按大小顺序插入的,那么我们可以在O(n)的时间内构造出这棵树,那么我们就按题目中所给数字大小顺序插入,fix值为其插入时间,就可以构造出符合题目的那棵树了。(key和fix给定时可以唯一确定一棵树)
1 #include<cstdio> 2 #define ll long long 3 using namespace std; 4 const int inf=3e5+10; 5 int fix[inf],n,fa[inf],dep[inf],a[inf]; 6 ll ans; 7 int main() 8 { 9 scanf("%d",&n); 10 for(int i=1;i<=n;i++){ 11 scanf("%d",&a[i]); 12 fix[a[i]]=i; 13 } 14 for(int i=1;i<=n;i++){ 15 int last=0,f=i-1; 16 while(fix[f]>fix[i])last=f,f=fa[f]; 17 fa[i]=f; 18 fa[last]=i; 19 } 20 dep[0]=-1; 21 for(int i=1;i<=n;i++){ 22 dep[a[i]]=dep[fa[a[i]]]+1; 23 ans+=dep[a[i]]; 24 printf("%lld\n",ans); 25 } 26 return 0; 27 }