思路:
给定n个节点二叉树的中序遍历,不同形态的二叉树的种类数有卡特兰数个。为了在中序序列[l, r]表示的子树上找先序序列第k小的树,首先需要从小到大枚举每个节点作根所能构成的二叉树的数目来确定树根。确定根之后,分别对左子树和右子树递归处理,具体见代码。
实现:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 typedef pair<int, int> pii; 5 ll c[31], k; 6 int a[31], n; 7 void dfs(int l, int r, ll k) 8 { 9 if (l > r) return; 10 vector<pii> v; 11 for (int i = l; i <= r; i++) v.push_back(pii(a[i], i)); 12 sort(v.begin(), v.end()); 13 ll tmp = 0, newk = 0; 14 int i = 0; 15 while (tmp < k) 16 { 17 int pos = v[i++].second - l + 1; 18 newk = k - tmp; 19 tmp += c[pos - 1] * c[v.size() - pos]; 20 } 21 int root = v[i - 1].second; 22 cout << a[root] << endl; 23 ll lc = c[root - l], rc = c[r - root]; 24 ll lk = (newk + rc - 1) / rc; 25 ll rk = (newk % rc == 0 ? rc : newk % rc); 26 dfs(l, root - 1, lk); dfs(root + 1, r, rk); 27 } 28 int main() 29 { 30 c[0] = c[1] = 1; 31 for (int i = 2; i <= 30; i++) 32 { 33 for (int j = 0; j < i; j++) 34 { 35 c[i] += c[j] * c[i - j - 1]; 36 } 37 } 38 cin >> n >> k; 39 for (int i = 1; i <= n; i++) cin >> a[i]; 40 dfs(1, n, k); 41 return 0; 42 }