【Luogu P3365】改造二叉树

题目链接

题目描述

在计算机科学中,二叉树是每个结点最多有两个子结点的有序树。通常子结点被称作“左孩子”和“右孩子”。二叉树被用作二叉搜索树和二叉堆。随后他又和他人讨论起了二叉搜索树。什么是二叉搜索树呢?二叉搜索树首先是一棵二叉树。设key[p]表示结点p上的数值。对于其中的每个结点p,若其存在左孩子lch,则key[p] > key[lch];若其存在右孩子rch,则key[p] < key[rch];注意,本题中的二叉搜索树应满足对于所有结点,其左子树中的key小于当前结点的key,其右子树中的key大于当前结点的key。(因为小L十分喜欢装xx,所以这里他十分装xx的给大家介绍了什么是二叉树和二叉搜索树)。

可是善于思考的小L不甘于只学习这些基础的东西。他思考了这样一个问题:现在给定一棵二叉树,可以任意修改结点的数值。修改一个结点的数值算作一次修改,且这个结点不能再被修改。若要将其变成一棵二叉搜索树,且任意时刻结点的数值必须是整数(可以是负整数或0),所要的最少修改次数。

题解

很简单可以想到把树上问题转化为序列上的问题,求出中序遍历即可。
然后我们可能想到求一个最长上升子序列,但仅这样是错误的。
因为数只能是整数且要严格递增,那么对于子序列中连续选择的两个数ai,aj来说,必须满足,aj-ai>=j-i 。
其实一个常见的将严格递增整数序列映射成非严格递增整数序列的技巧就是将如下序列:
a1, a2, a3, a4 … an 映射成:
a1 - 1, a2 - 2, a3 - 3, a4 - 4 … an - n.
(这种方法常见于计数类问题)。
这样映射后求最长不下降子序列的长度就没问题了。

其实这也可以由上面的式子变形得来,aj-ai>=j-i 即 aj-j>=ai-i (即使式子很简单,写出并适当变形后也可能有大用处)
这表示若两个数ai,aj满足 aj-j>=ai-i ,那么aj可以接在ai后面
最后答案是 n-len (最长不降子序列的)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#define Set(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=1e5+10;
struct node{
    int ls,rs;int fa;int x;
    void clear(){ls=rs=fa=x=0;}
}tr[N];
typedef long long ll;
ll a[N];
inline int read()
{
    int x=0;char ch=getchar();int t=1;
    for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch-48);
    return x*t;
}
int n;
int cnt=0;
ll st[N];int top=0;
const ll INF=21474836479;
inline void dfs(int now)
{
    if(tr[now].ls!=0) dfs(tr[now].ls);
    a[++cnt]=tr[now].x;
    if(tr[now].rs!=0) dfs(tr[now].rs);
    return ;
}
//返回迭代器的,取下表则不减1,取元素个数则要减1
inline void solve()
{
    for(register int i=1;i<=n;++i)
    {
        if((!top)||a[i]>=st[top]) st[++top]=a[i];
        else{
            register int k=upper_bound(st+1,st+1+top,a[i])-st;
            if(k<=top) st[k]=a[i];
        }
    }
    printf("%d\n",n-top);
}
int main()
{
    n=read();
    for(register int i=1;i<=n;i++) tr[i].clear(),tr[i].x=read();
    register int ch;
    for(register int i=2;i<=n;++i)
    {
        tr[i].fa=read();ch=read();
        if(ch==0) tr[tr[i].fa].ls=i;
        else tr[tr[i].fa].rs=i;
    }
    dfs(1);
    for(register int i=1;i<=n;++i) a[i]-=i;
    solve();
}

猜你喜欢

转载自blog.csdn.net/element_hero/article/details/80375354
今日推荐