[noip模拟]改造二叉树LIS
1.改造二叉樹(shù)
【題目描述】
小Y在學(xué)樹(shù)論時(shí)看到了有關(guān)二叉樹(shù)的介紹:在計(jì)算機(jī)科學(xué)中,二叉樹(shù)是每個(gè)結(jié)點(diǎn)最多有兩個(gè)子結(jié)點(diǎn)的有序樹(shù)。通常子結(jié)點(diǎn)被稱作“左孩子”和“右孩子”。二叉樹(shù)被用作二叉搜索樹(shù)和二叉堆。隨后他又和他人討論起了二叉搜索樹(shù)。
什么是二叉搜索樹(shù)呢?二叉搜索樹(shù)首先是一棵二叉樹(shù)。設(shè)key[p]表示結(jié)點(diǎn)p上的數(shù)值。對(duì)于其中的每個(gè)結(jié)點(diǎn)p,若其存在左孩子lch,則key[p]>key[lch];若其存在右孩子rch,則key[p]<key[rch];注意,本題中的二叉搜索樹(shù)應(yīng)滿足對(duì)于所有結(jié)點(diǎn),其左子樹(shù)中的key小于當(dāng)前結(jié)點(diǎn)的key,其右子樹(shù)中的key大于當(dāng)前結(jié)點(diǎn)的key。
小Y與他人討論的內(nèi)容則是,現(xiàn)在給定一棵二叉樹(shù),可以任意修改結(jié)點(diǎn)的數(shù)值。修改一個(gè)結(jié)點(diǎn)的數(shù)值算作一次修改,且這個(gè)結(jié)點(diǎn)不能再被修改。若要將其變成一棵二叉搜索樹(shù),且任意時(shí)刻結(jié)點(diǎn)的數(shù)值必須是整數(shù)(可以是負(fù)整數(shù)或0),所要的最少修改次數(shù)。
相信這一定難不倒你!請(qǐng)幫助小Y解決這個(gè)問(wèn)題吧。
?
【輸入格式】
第一行一個(gè)正整數(shù)n表示二叉樹(shù)結(jié)點(diǎn)數(shù)。結(jié)點(diǎn)從1~n進(jìn)行編號(hào)。
第二行n個(gè)正整數(shù)用空格分隔開(kāi),第i個(gè)數(shù)ai表示結(jié)點(diǎn)i的原始數(shù)值。
此后n - 1行每行兩個(gè)非負(fù)整數(shù)fa, ch,第i + 2行描述結(jié)點(diǎn)i + 1的父親編號(hào)fa,以及父子關(guān)系ch,(ch = 0 表示i + 1為左兒子,ch = 1表示i + 1為右兒子)。
結(jié)點(diǎn)1一定是二叉樹(shù)的根。
?
【輸出格式】
僅一行包含一個(gè)整數(shù),表示最少的修改次數(shù)。
?
【樣例輸入】
3
2 2 2
1 0
1 1
?
【樣例輸出】
2
?
【數(shù)據(jù)范圍】
20 % :n <= 10 , ai <= 100.
40 % :n <= 100 , ai <= 200
60 % :n <= 2000 .
100 % :n <= 10 ^ 5 , ?ai < 2 ^ 31.?
?
對(duì)樹(shù)的知識(shí)了解的人可能一下就可以反應(yīng)過(guò)來(lái),我們針對(duì)一個(gè)小的分支看,是左邊<父節(jié)點(diǎn)<右邊。。。。然后這個(gè)順序想到了啥
對(duì),就是中序遍歷,中序遍歷:左中右。。。。然后題中也說(shuō)到,整個(gè)左子樹(shù)要小于父節(jié)點(diǎn)
然后我們就能夠推出來(lái),改造二叉樹(shù)的中序遍歷是嚴(yán)格上升的
然后題就轉(zhuǎn)換成了求中序遍歷,然后求最長(zhǎng)嚴(yán)格上升子序列。。。。
求最長(zhǎng)嚴(yán)格上升子序列可以進(jìn)行優(yōu)化,因?yàn)槭菄?yán)格上升,所以第i個(gè)至少比第i-1個(gè)大1,然后我們可以對(duì)這個(gè)序列里的數(shù)減去他的序數(shù),就是求最長(zhǎng)不下降子序列
?
這題還有一個(gè)需要注意的地方是,數(shù)據(jù)范圍太大,不適合普通的LIS做法,要進(jìn)行優(yōu)化。。。
優(yōu)化方式是開(kāi)個(gè)數(shù)組f[i]記錄滿足條件的第i個(gè)數(shù)最小是f[i]
我們畫(huà)圖理解
然后我們唯一要處理就是圖中第一個(gè)6和4 對(duì)f的影響
這里我們可以用二分的方式,因?yàn)槭巧仙有蛄?#xff0c;所以我們只需要二分找到第一個(gè)比當(dāng)前小的數(shù),然后用當(dāng)前數(shù)取代之前那個(gè)數(shù)
圖中就是,當(dāng)i=4時(shí),二分找到第一個(gè)比他小的i=1,a[i]=1的數(shù),然后發(fā)現(xiàn)a[2]<a[4]就用2取代這個(gè)位置的6,f[2]=6,9的取代同理
這樣做就大大優(yōu)化了時(shí)間,不會(huì)超時(shí)
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cmath> 6 #include<cstdlib> 7 #include<queue> 8 #define maxn 100005 9 using namespace std; 10 11 struct node{ 12 int l,r,val; 13 }tree[maxn]; 14 15 int n,a[maxn],f[maxn],ans,tot; 16 17 void dfs(int pos){//中序遍歷左中右 18 if(pos<1)return; 19 dfs(tree[pos].l); 20 tot++; 21 a[tot]=tree[pos].val-tot;//求最長(zhǎng)不下降子序列 22 dfs(tree[pos].r); 23 } 24 25 int find(int l,int r,int x) 26 { 27 while(l<=r){ 28 int mid=(l+r)/2; 29 if(f[mid]<=x)l=mid+1; 30 else r=mid-1; 31 } 32 return l; 33 } 34 35 int main() 36 { 37 freopen("binary.in","r",stdin); 38 freopen("binary.out","w",stdout); 39 scanf("%d",&n); 40 for(int i=1;i<=n;i++){ 41 scanf("%d",&tree[i].val); 42 }int fa,so; 43 for(int i=2;i<=n;i++){ 44 scanf("%d%d",&fa,&so); 45 if(so==0)tree[fa].l=i; 46 else tree[fa].r=i; 47 } 48 dfs(1); 49 f[1]=a[1];ans=1; 50 for (int i=2;i<=n;i++)//最長(zhǎng)不降字串一類的信方式 51 { 52 if (a[i]>=f[ans]) 53 f[++ans]=a[i]; 54 else 55 f[find(1,ans,a[i])]=a[i];//當(dāng)合法字串長(zhǎng)度一樣,盡量用小的那一個(gè) 56 } 57 printf("%d\n",n-ans); 58 /* 59 6 60 4 6 5 1 9 6 61 1 0 62 1 1 63 2 0 64 2 1 65 3 1 66 */ 67 } View Code總結(jié):在遇到和樹(shù)相關(guān)的題時(shí),如果允許,可以從前中后遍歷去查詢問(wèn)題。。。
最長(zhǎng)上升或不降這一類的題,可以進(jìn)行優(yōu)化,優(yōu)化方式如文。。。
還有一點(diǎn)就是可以合理運(yùn)用容斥原理,我們這是求最少不合法的個(gè)數(shù),然后可以轉(zhuǎn)換成總數(shù)減去合法的最大個(gè)數(shù)
?
轉(zhuǎn)載于:https://www.cnblogs.com/Danzel-Aria233/p/7646763.html
總結(jié)
以上是生活随笔為你收集整理的[noip模拟]改造二叉树LIS的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: JS:2.1,流程控制(if,switc
- 下一篇: 物联网协议之CoAP协议开发学习笔记之术