改造二叉树

来源:互联网 发布:linux 屏幕 测试 编辑:程序博客网 时间:2024/05/02 03:04

题目

小Y在学树论时看到了有关二叉树的介绍:在计算机科学中,二叉树是每个结点最多有两个子结点的有序树。通常子结点被称作“左孩子”和“右孩子”。二叉树被用作二叉搜索树和二叉堆。随后他又和他人讨论起了二叉搜索树。
什么是二叉搜索树呢?二叉搜索树首先是一棵二叉树。设key[p]表示结点p上的数值。对于其中的每个结点p,若其存在左孩子lch,则key[p]>key[lch];若其存在右孩子rch,则key[p]

题意

给你一棵普通的二叉树,让你变成一棵二叉排序树(搜索树)需要至少改变多少次。

分析

我们可以先画个图,我们会发现一个重要的事:
若一棵二叉树按中序遍历排序时一个最长不上升的序列,那么这是一棵二叉搜索树
那么我们会想到去用原先的二叉树去排中序遍历后去做最长不下降子序列,然后用总节点个数-最长不下降个数便为答案了。
但是这是不够的,题目的限制是整数
那么2,3,1,4这个序列的答案便是1,但实际是2
我们要继续寻找解决的方法,刚刚的问题是两数之间没有整数,那么:
a,b,a+1,那么很明显b是不合法的,那么我们如何限制它呢?
我们可以把它们减去它们的下标(即A1-1,A2-2,A3-3….An-n)
为什么这样是可以的呢?
因为:
若有两个数ai,aj,(分别为b,b+n)且这两个数是在最长不下降子序列中的
那么b,b+n之间有j-i-1个整数,但是实际只能插上n-1个数。
所以就是这样

var    fa,a,f,b,d:array[0..100000] of longint;    son:array[0..100000,1..2] of longint;    i,n,m,x,y,l,r,mid,en,st:longint;function min(l,r:longint):longint;begin    if l>r then exit(r) else exit(l);end;procedure dfs(k:longint);begin    if k=0 then exit;    dfs(son[k,1]);    inc(st);b[st]:=a[k];    dfs(son[k,2]);end;begin     readln(n);     for i:=1 to n do read(a[i]);     for i:=2 to n do begin         read(x,y);         if y=1 then son[x,2]:=i else son[x,1]:=i;         fa[i]:=x;     end;     dfs(1);     for i:=1 to st do b[i]:=b[i]-i;     en:=1;d[1]:=b[1];     for i:=2 to st do begin         if b[i]>=d[en] then begin inc(en);d[en]:=b[i];end         else begin             l:=1;r:=en;             while l<>r do begin                mid:=(l+r)shr 1;                if d[mid]<=b[i] then l:=mid+1 else r:=mid;             end;             d[l]:=min(d[l],b[i]);         end;     end;     writeln(n-en);end.
0 0