题目大意
给出一颗二叉树及其
个节点的权值,每个节点权值最多修改一次,且只能修改成整数。求最小的修改次数,使这棵二叉树成为排序二叉树。
首先,排序二叉树是一种左儿子权值严格小于父亲,右儿子权值严格大于父亲的二叉树( )。所谓“排序”,就是先序遍历排序二叉树,得到的是一个严格递增的序列。
那么我们显然要先先序遍历一趟,构造出
数组,那么题目就变成求使一个序列变为严格递增所需的最少修改次数
所以答案就为
但是,
题目要求每个节点的权值只能改为整数!只要有“卡死”的重复元素,就完蛋了
如这个样例就崩溃了:
我们再思考一下:
修改完后,显然
即
所以显然对于
,有
,即
那如果将每个Ai抠掉i,则
此时,就没有重复的元素影响了
只要
求一趟最长不降子序列就OK了
#include<cstdio>
#define LL long long
using namespace std;
const int maxn=(1e5)+5;
int n,tal;LL que[maxn],a[maxn];
struct ff{
int L,R,x;
}c[maxn];
char gt(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
int read(){
int ret=0;bool f=0;char ch=gt();
while(ch<'0'||ch>'9') f|=(ch=='-'),ch=gt();
while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=gt();
return f?-ret:ret;
}
void DFS(int x){
if(c[x].L) DFS(c[x].L);
a[++a[0]]=c[x].x;
if(c[x].R) DFS(c[x].R);
}
void find(LL x){
if(x>=que[tal]){que[++tal]=x;return;}
int L=1,R=tal,mid;
while(L<=R){
mid=L+R>>1;
if(que[mid-1]<=x&&x<que[mid]){que[mid]=x;return;}
if(x<que[mid-1]) R=mid-1;else L=mid+1;
}
}
int main(){
n=read();
for(int i=1;i<=n;i++) c[i].x=read();
for(int i=2;i<=n;i++){
int fa=read(),flg=read();
if(flg) c[fa].R=i;else c[fa].L=i;
}
DFS(1);
que[0]=-((LL)1<<60);
for(int i=1;i<=n;i++) find(a[i]-i);
printf("%d\n",n-tal);
return 0;
}