堆 (heap)
Description
给你一棵有n层的满二叉树,要求父亲的权值大于等于儿子的权值,并且左子树的任意一个结点的权值都小于等于右子树任意一个节点的权值。
但是这棵二叉树可能不满足这个条件,现在你需要对若干结点的权值进行调整使得它满足这个条件;并且你希望调整的节点最少。
Input
第一行一个正整数n。
接下来有n行,第n行有2^(i-1)个正整数,依次表示从左向右第i 层的节点的权值(≤10^9)。
Output
一行一个非负整数,表示最少需要调整的节点的数量。
Hint
样例解释 :
我们可以把3调整为1或2,或者把2调整为任意一个大于等于3的数。
数据范围 :
考虑数的后序遍历,答案等于2^n-1-最长不降子序列长度(各位感性理解一波?!)
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
struct ed{int l,r,c;}tr[10000000];
int n,t,p,a[10000000],f[10000000],dp[10000000];
void build(int x){//建树
if(x>n) return;
tr[x].c=a[x];
tr[x].l=2*x;tr[x].r=2*x+1;
build(2*x);build(2*x+1);
}
void hdfs(int x){//后序遍历
if(x<=n){
hdfs(tr[x].l);hdfs(tr[x].r);
f[++t]=tr[x].c;
}
return;
}
int main()
{
scanf("%d",&n);
n=pow(2,n)-1;
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
build(1);hdfs(1);
dp[1]=f[1];p=1;
for (int i=2;i<=n;i++){
if (f[i]>=dp[p]) dp[++p]=f[i];
else {
int j=upper_bound(dp+1,dp+p+1,f[i])-dp;
dp[j]=f[i];
}
}
cout<<n-p;
return 0;
}