p3365改造二叉树

 

 化简题意:给出一棵二叉树,每个点有一个权值,求最少改造为严格二叉查找树(不能等于)的节点数。

首先,我感觉我已经非常靠近正解了。

考场就已经想到了所有模型,但是却没有想到正解的dp,歪歪了一个树形dp,然后拿到了5分的好成绩....

直入主题:

首先,一颗二叉查找树的性质就是:中序遍历出来的序列一定是一个递增序列。

这点很好想,然后我们要找一些不符合这个性质的,把它们修改一下,变成序列。

于是,只要你熟悉dp模型,就可以看出来

$$咦?这不是最长不下降子序列吗?$$

是的,但是,它需要严格单调递增。

这点就很烦了....

这时,需要手玩一下式子:

设节点的编号分别为$a1,a2,a3.....an$,

序列是这样的:

$a_{1}<a_{2}<a_{3}<....<a_{n}$

这时严格递增,没法写。

想着怎么把它换成非严格递增:

因为a是整数,所以:

$a_{1}<=a_{2}-1$,$a_{2}<=a_{3}-1$......$a_{n-1}<a_{n}$

所以,出现这样的式子:

$a_{1}-1<=a_{2}-2<=a_{3}-3<=....<=a_n-n$

这样,序列就转化为了非严格上升,也就是最长不下降子序列,

问题就解决了。

#include<bits/stdc++.h>
using namespace std;
int n;
const int maxn=5e5+10;
int a[maxn];
struct tree
{
    int ls,rs,v,size;
  
}t[maxn];
  
int tw[maxn];
int cnt;
int ans;
void dfs(int rt)//中序遍历
{
    if(t[rt].ls!=0)
    dfs(t[rt].ls);
    tw[++cnt]=t[rt].v;
    if(t[rt].rs!=0)
    dfs(t[rt].rs);
}
  
void c(tree a)//初始化
{
    a.ls=a.size=a.v=a.rs=0;
}
int q[maxn];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        c(t[i]);
    }
    t[1].v=a[1];
    for(int i=2;i<=n;i++)
    {
        int fa,ch;
        scanf("%d%d",&fa,&ch);
        if(ch==0)
        t[fa].ls=i;
        else
        t[fa].rs=i;
        t[i].v=a[i];
    }
    dfs(1);
    for(int i=1;i<=cnt;i++)
    tw[i]-=i;
    q[1]=tw[1];
    int tot=1;
    for(int i=2;i<=n;i++)
    {
        if (tw[i]>=q[tot]) q[++tot]=tw[i];
        else
        {
            int x=upper_bound(q+1,q+tot+1,tw[i])-q;
            q[x]=tw[i];
        }
    }
    printf("%d",n-tot);
    return 0;
}

(完)

原文地址:https://www.cnblogs.com/ajmddzp/p/11857554.html