P3365 改造二叉树

题目背景

勤奋又善于思考的小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.

Solution:

  本题要使原树变为一棵二叉搜索树,等价于中序遍历这棵树,将得到的区间用最少的次数修改为严格上升序列。

  那么我们建树后先求出区间,很容易想到修改次数$=$总的区间长度$-$最长上升子序列的长度,但是很显然会有问题,因为本题修改前后都是整数,如果直接按上面去求,对于$1,2,2,3$这类数据,会算得$4-3=1$,而很显然正确答案应该是$4-2=2$,原因是修改会出现冲突(即修改后两个数相同)。怎么解决这个问题呢?我们发现,严格单调上升,每个数至少和前一个数差一,每个位置上的数会受到前面的数限制,于是我们以第一个数为基础去做一个类似差分的操作,$a[i]-=(i-1)$,意味着第$i$位至少要比$a[1]$大$i-1$(即若第$3$位的数为$4$,那么第$3$位变为$2$,因为第$3$位至少比第一位数大$2$)。那么在新的差分的序列中求一下最长不下降子序列就$OK$了(由于数据比较大,需要二分,复杂度$O(nlogn)$)。

代码:

 1 #include<bits/stdc++.h>
 2 #define il inline
 3 #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
 4 using namespace std;
 5 const int N=1e5+5;
 6 int n,ans,w[N],ch[N][2],x,p,a[N],cnt,f[N],len;
 7 il int gi(){
 8     int a=0;char x=getchar();bool f=0;
 9     while((x<‘0‘||x>‘9‘)&&x!=‘-‘)x=getchar();
10     if(x==‘-‘)x=getchar(),f=1;
11     while(x>=‘0‘&&x<=‘9‘)a=(a<<3)+(a<<1)+x-48,x=getchar();
12     return f?-a:a;
13 }
14 il void dfs(int x){
15     if(!ch[x][0]&&!ch[x][1]){a[++cnt]=w[x];return;}
16     if(ch[x][0])dfs(ch[x][0]);
17     a[++cnt]=w[x];
18     if(ch[x][1])dfs(ch[x][1]);
19 }
20 int main(){
21     n=gi();
22     For(i,1,n)w[i]=gi();
23     For(i,2,n){
24         x=gi(),p=gi();
25         ch[x][p]=i;
26     }
27     dfs(1);
28     For(i,1,n)a[i]-=(i-1);
29     f[1]=a[1];len=1;f[0]=-2052052020;
30     int k,l,r,mid;
31     For(i,2,n){
32         if(f[len]<=a[i])k=(++len);
33         else {
34             l=0,r=len;
35             while(l<=r){
36                 mid=l+r>>1;
37                 if(a[i]>=f[mid]&&a[i]<f[mid+1]){k=mid;break;}
38                 else if(a[i]>=f[mid])l=mid+1;
39                 else r=mid-1;
40             }
41             k++;
42         }
43         ans=max(ans,k);f[k]=a[i];
44     }
45     cout<<n-ans;
46     return 0;
47 }

原文地址:https://www.cnblogs.com/five20/p/9062706.html

时间: 2024-10-12 03:02:09

P3365 改造二叉树的相关文章

10.26最后的模拟:改造二叉树

改造二叉树 [题目描述] 小Y在学树论时看到了有关二叉树的介绍:在计算机科学中,二叉树是每个结点最多有两个子结点的有序树.通常子结点被称作“左孩子”和“右孩子”.二叉树被用作二叉搜索树和二叉堆.随后他又和他人讨论起了二叉搜索树. 什么是二叉搜索树呢?二叉搜索树首先是一棵二叉树.设key[p]表示结点p上的数值.对于其中的每个结点p,若其存在左孩子lch,则key[p]>key[lch]:若其存在右孩子rch,则key[p]<key[rch]:注意,本题中的二叉搜索树应满足对于所有结点,其左子树

改造二叉树

题目背景 勤奋又善于思考的小L接触了信息学竞赛,开始的学习十分顺利.但是,小L对数据结构的掌握实在十分渣渣. 所以,小L当时卡在了二叉树. 题目描述 在计算机科学中,二叉树是每个结点最多有两个子结点的有序树.通常子结点被称作“左孩子”和“右孩子”.二叉树被用作二叉搜索树和二叉堆.随后他又和他人讨论起了二叉搜索树.什么是二叉搜索树呢?二叉搜索树首先是一棵二叉树.设key[p]表示结点p上的数值.对于其中的每个结点p,若其存在左孩子lch,则key[p]>key[lch]:若其存在右孩子rch,则k

JZOJ 3894. 改造二叉树

题目 Description 小Y在学树论时看到了有关二叉树的介绍:在计算机科学中,二叉树是每个结点最多有两个子结点的有序树.通常子结点被称作“左孩子”和“右孩子”.二叉树被用作二叉搜索树和二叉堆.随后他又和他人讨论起了二叉搜索树.什么是二叉搜索树呢?二叉搜索树首先是一棵二叉树.设key[p]表示结点p上的数值.对于其中的每个结点p,若其存在左孩子lch,则key[p]>key[lch]:若其存在右孩子rch,则key[p]<key[rch]:注意,本题中的二叉搜索树应满足对于所有结点,其左子

10day2

最多因子数 搜索 [问题描述] 数学家们喜欢各种类型的有奇怪特性的数.例如,他们认为 945 是一个有趣的数,因为它是第一个所有约数之和大于本身的奇数. 为了帮助他们寻找有趣的数,你将写一个程序扫描一定范围内的数,并确定在此范围内约数个数最多的那个数.不幸的是,这个数和给定的范围的都比较大,用简单的方法寻找可能需要较多的运行时间.所以请确定你的算法能在几秒内完成最大范围内的扫描. [输入] 只有一行,给出扫描的范围,由下界 L 和上界 U 确定.满足 2≤L≤U≤1000000000. [输出]

8.12联考题解

所谓今天的题格外水,dalao们纷纷AK--但是本蒟蒻并没有看出来有多水啊--虽然还是水过了一道题,然后剩下的题就照常地转不过来弯,分数和往常并没有多大变化= =. 灌水 时间限制:1s 空间限制:256MB 样例输入1: 3 1 样例输出1: 3 1 2 样例输入2: 4 1 样例输出2: 4 3 1 2 样例输入3: 8 17 样例输出3: 6 2 3 1 8 4 5 7 题解       这个题,第一眼看过去很interesting,第二眼看过去一脸茫然--头一遍读题的时候看到数据范围里那

NOIP2017SummerTraining0717

个人感受:自己水平是真的差劲,和他们不是一个档次的,第二题,如果不是陈载元暴力过了,我也不会那么早去A了第二题,第一题真的是无语,以前做到过,还想到了每个对应值a[i]-i,但是没想出来,真的是 可惜,这套题的话前两题都比提高组的要水,但这样下去,别说省选,TG一等都难拿. 改造二叉树 时间限制: 1 Sec  内存限制: 256 MB提交: 365  解决: 95[提交][状态][讨论版] 题目描述 小Y在学树论时看到了有关二叉树的介绍:在计算机科学中,二叉树是每个结点最多有两个子结点的有序树

二模10day2解题报告

T1.最多因子数(divisors) 给出范围l,r求其中约数和最大的最小整数. 非常深井冰的题目:如果特判加暴力的话分数低的可怜 AC做法要用到分解质因数和线性筛(这俩好写),然而,一个一个枚举还是不可避免的TLE了(最后一个点1,1000000000可怕). 其实考虑一下,如果n为合数且是x的约数,那么n的约数也是x的约数,所以重复计算了很多.要避免这种情况就要改dfs,在计算过程中保存最多的和最多的约数个数.(然而并不是那么好打的) T2.改造二叉树(bst) 给出n个节点的二叉树,以及每

常用排序算法的python实现和性能分析

http://www.cnblogs.com/wiki-royzhang/p/3614694.html 一年一度的换工作高峰又到了,HR大概每天都塞几份简历过来,基本上一天安排两个面试的话,当天就只能加班干活了.趁着面试别人的机会,自己也把一些基础算法和一些面试题整了一下,可以阶段性的留下些脚印——没办法,平时太忙,基本上没有时间写博客.面试测试开发的话,这些也许能帮得上一些. 这篇是关于排序的,把常见的排序算法和面试中经常提到的一些问题整理了一下.这里面大概有3个需要提到的问题: 虽然专业是数

9.2noip模拟试题

  题目名称 改造二叉树 数字对 交换 英文名称 binary pair swap 输入文件名 binary.in pair.in swap.in 输出文件名 binary.out pair.out swap.out 时间限制 1s 2s 1s 空间限制 256M 256M 256M 测试点数目 20 20 10 测试点分值 5 5 10 是否有部分分 无 无 无 题目类型 传统 传统 传统 是否有SPJ 无 无 无 1.改造二叉树 [题目描述] 小Y在学树论时看到了有关二叉树的介绍:在计算机科