日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

洛谷 P1377 [TJOI2011]树的序 解题报告

發布時間:2024/7/19 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 洛谷 P1377 [TJOI2011]树的序 解题报告 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

P1377 [TJOI2011]樹的序

題目描述

眾所周知,二叉查找樹的形態和鍵值的插入順序密切相關。準確的講:1、空樹中加入一個鍵值\(k\),則變為只有一個結點的二叉查找樹,此結點的鍵值即為\(k\);2、在非空樹中插入一個鍵值\(k\),若\(k\)小于其根的鍵值,則在其左子樹中插入\(k\),否則在其右子樹中插入\(k\)

我們將一棵二叉查找樹的鍵值插入序列稱為樹的生成序列,現給出一個生成序列,求與其生成同樣二叉查找樹的所有生成序列中字典序最小的那個,其中,字典序關系是指對兩個長度同為\(n\)的生成序列,先比較第一個插入鍵值,再比較第二個,依此類推。

輸入輸出格式

輸入格式:

第一行,一個整數,\(n\),表示二叉查找樹的結點個數。第二行,有\(n\)個正整數,\(k_1\)\(k_n\),表示生成序列,簡單起見,\(k_1\)~\(k_n\)為一個1到\(n\)的排列。

輸出格式:

一行,\(n\)個正整數,為能夠生成同樣二叉查找數的所有生成序列中最小的。

說明

對于20%的數據,n ≤ 10。

對于50%的數據,n ≤ 100。

對于100%的數據,n ≤ 100,000。


先化簡一下模型,我們把\(BST\)樹建好,然后輸出中序遍歷即是答案。

然而,直接建\(BST\)是很容易退化成鏈的。

做過題目多的人可能聽說過,這個叫笛卡爾樹

笛卡爾樹是一種既滿足堆性質又滿足二叉排序樹性質的樹。

方法一:普通笛卡爾樹的建樹方法

現在有一個序列按二叉排序樹的關鍵字\(Key\)從小到大有序,序列中包含小跟堆的關鍵字\(Index\)關鍵字,在\(O(N)\)的時間建樹。

按原數列順序一個一個將節點加入笛卡爾樹,可以確定一定是從鏈的右邊向下找到一個\(Index\)大于這個點的節點,把這個節點位置占據,然后置讓Ta當自己的左兒子即可。

用棧把最右邊的鏈存下來,棧頂為右邊最底的那個點,加入時邊彈出邊向上找,更新好位置關系后把自己存進棧即可。

code:

#include <cstdio> #include <algorithm> #define ls t[now].ch[0] #define rs t[now].ch[1] #define f t[now].par const int N=100010; struct node {int dat,index;bool friend operator <(node n1,node n2){return n1.dat<n2.dat;} }a[N]; struct BST {int ch[2],dat,index,par;//左右兒子,BST域,堆域,父親 }t[N]; int tot=0,n,s[N]; void connect(int fa,int now,int typ) {f=fa;t[fa].ch[typ]=now; } void dfs(int now) {if(!now) return;printf("%d ",t[now].dat);dfs(ls);dfs(rs); } int main() {scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",a+i);a[i].index=i;}std::sort(a+1,a+1+n);for(int i=1;i<=n;i++){int last=0;while(tot&&t[s[tot]].index>a[i].index)last=tot--;t[i].dat=a[i].dat;t[i].index=a[i].index;connect(s[tot],i,1);connect(i,s[last],0);s[++tot]=i;}dfs(t[0].ch[1]);return 0; }

方法二:按堆性質自底向上建立。
這個方法好厲害,真的很強。

則如果兩個點的\(Key\)在“當前”數值上的差最小,那么Ta倆一定有一條邊。

\(Index\)從大到小建立笛卡爾樹,則對\(1\)-\(Index-1\)的點中,是不會有\(Index\)的兒子的。

\(pre[i]\)\(suc[i]\)分別存儲\(Key\)\(i\)的點在“當前”所相鄰的前驅和后繼。

每次處理完一個點,更新與它相連的“前驅”和“后繼”,這對應了“當前”

注意到原數據為1到n的排列,可以用桶排,比較快。

Code:

#include <cstdio> const int N=100010; int a[N],b[N],L[N],R[N],pre[N],suc[N],n; void dfs(int now) {if(!now) return;printf("%d ",a[now]);dfs(L[now]);dfs(R[now]); } int main() {scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",a+i);b[a[i]]=i;pre[i]=i-1,suc[i]=i+1;}for(int i=n;i>1;i--){int pree=pre[a[i]],succ=suc[a[i]];if(b[pree]>b[succ])R[b[pree]]=i;elseL[b[succ]]=i;suc[pree]=succ;pre[succ]=pree;}dfs(1);return 0; }

2018.6.19

轉載于:https://www.cnblogs.com/butterflydew/p/9199591.html

總結

以上是生活随笔為你收集整理的洛谷 P1377 [TJOI2011]树的序 解题报告的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。