洛谷U4727小L的二叉樹[樹轉序列 LIS]

Candy?發表於2016-09-18

題目背景

勤奮又善於思考的小L接觸了資訊學競賽,開始的學習十分順利。但是,小L對資料結構的掌握實在十分渣渣。

所以,小L當時卡在了二叉樹。

題目描述

在電腦科學中,二叉樹是每個結點最多有兩個子結點的有序樹。通常子結點被稱作“左孩子”和“右孩子”。二叉樹被用作二叉搜尋樹和二叉堆。隨後他又和他人討論起了二叉搜尋樹。什麼是二叉搜尋樹呢?二叉搜尋樹首先是一棵二叉樹。設key[p]表示結點p上的數值。對於其中的每個結點p,若其存在左孩子lch,則key[p]>key[lch];若其存在右孩子rch,則key[p]<key[rch];注意,本題中的二叉搜尋樹應滿足對於所有結點,其左子樹中的key小於當前結點的key,其右子樹中的key大於當前結點的key。(因為小L十分喜歡裝xx,所以這裡他十分裝xx的給大家介紹了什麼是二叉樹和二叉搜尋樹)。

可是善於思考的小L不甘於只學習這些基礎的東西。他思考了這樣一個問題:現在給定一棵二叉樹,可以任意修改結點的數值。修改一個結點的數值算作一次修改,且這個結點不能再被修改。若要將其變成一棵二叉搜尋樹,且任意時刻結點的數值必須是整數(可以是負整數或0),所要的最少修改次數。

這一定難不倒聰明的你吧!如果你能幫小L解決這個問題,也許他會把最後的資產分給你1/16哦!

輸入輸出格式

輸入格式:

 

第一行一個正整數n表示二叉樹節點數。

第二行n個正整數用空格分隔開,第i個數ai表示結點i的原始數值。

此後n - 1行每行兩個非負整數fa, ch,第i + 2行描述結點i + 1的父親編號fa,以及父子關係ch,(ch = 0 表示i + 1為左兒子,ch = 1表示i + 1為右兒子)。

為了讓你稍微減輕些負擔,小L規定:結點1一定是二叉樹的根哦!

 

輸出格式:

 

僅一行包含一個整數,表示最少的修改次數

 

輸入輸出樣例

輸入樣例#1:
3
2 2 2
1 0
1 1
輸出樣例#1:
2

說明

20 % :n <= 10 , ai <= 100.

40 % :n <= 100 , ai <= 200

60 % :n <= 2000 .

100 % :n <= 10 ^ 5 ,  ai < 2 ^ 31. 


 

沒想出來,參考幾年前一道模擬題

左中右,不就是中序遍歷嘛

求一下中序遍歷,再在這上面求LIS,n-LIS不就是答案嘛

但是有一個問題,2,1,3,這樣的不能一次得到答案,因為必須嚴格單增

所以又用到了a[i]-i變為不嚴格單增

//
//  main.cpp
//  luogu9.1
//
//  Created by Candy on 9/17/16.
//  Copyright © 2016 Candy. All rights reserved.
//

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+5,INF=2147483647;
int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
    return x*f;
}
int n,a[N],fa,ch;
struct node{
    int ch[2],a;
}t[N];
int cnt=0;
void inOrder(int u){
    if(t[u].ch[0]) inOrder(t[u].ch[0]);
    a[++cnt]=t[u].a-cnt;
    if(t[u].ch[1]) inOrder(t[u].ch[1]);
}
int g[N],d[N],ans=0;
void lis(){
    for(int i=1;i<=n;i++) g[i]=INF;
    for(int i=1;i<=n;i++){
        int k=lower_bound(g+1,g+1+n,a[i])-g;
        d[i]=k;
        g[k]=a[i];
        ans=max(ans,d[i]);
    }
}
int main(int argc, const char * argv[]) {
    n=read();
    for(int i=1;i<=n;i++) t[i].a=read();
    for(int i=2;i<=n;i++){
        fa=read();ch=read();
        t[fa].ch[ch]=i;
    }
    inOrder(1);
//    for(int i=1;i<=n;i++) printf("%d ",a[i]);
    lis();
    printf("%d",n-ans);
    return 0;
}

 

相關文章