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;
}
(完)