zoukankan      html  css  js  c++  java
  • 洛谷U4727小L的二叉树[树转序列 LIS]

    题目背景

    勤奋又善于思考的小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;
    }
  • 相关阅读:
    第七周作业
    人月神话之没有银弹
    第六周作业
    第五周作业
    第四周作业
    第三周作业
    人月神话之沟通
    第二周作业
    第一周作业
    第八周作业
  • 原文地址:https://www.cnblogs.com/candy99/p/5883429.html
Copyright © 2011-2022 走看看