雪中楼§
由于高度必定各不相同,我们可以把高度看成n的全排列。
我们考虑每一个点,一旦当前点被之后的点索引,意味着之后的那些点必定高于该点。
由于题目中的如果该点被索引,那么它就是小于并且在索引它的点的前面的点的集和中的最大值。
如果多个点索引同一个点,那么它们的高度是严格递减的。
我们可以考虑用dfs进行递归,从前往后分配高度,先分配的高度比后分配的高度严格大1。
当循环到当前位置时,我们会dfs索引它的点的集合,然后对里面的点继续进行这样的dfs操作,当没有人比它大或者比它大的已经赋完值了,再对该点进行赋值。
注意递归赋值后外循环遍历到已赋值的位置要continue。
对于任意索引别人的点来说它要更先于其索引的点进行赋值(我们是递减赋值的过程)。
我们在想按以上方法递归地操作完以后,会有遗漏的比我大的值没被更新过吗?
首先如果这个大值在我前面肯定会被更新过,如果它在我后面,它要么索引我,要么索引比我大的值。
显然索引我必定在我之前更新,如果索引比我大的值,这个值在我前面,肯定也没问题,在我后面的话,我们就会递归的继续讨论这个,毕竟它比我们大。
到最后这个递归下去的最大值要么会因为索引在我们前面而截至要么一直塞在我们后面无限接近我们,最后严格挨着我们,那时也只能索引到我们自己。
逻辑自洽。既然dfs里递归操作的每一步都会满足,那么我们递减赋值所赋值给的位置就应该是正确的位置。
由此证明完毕。
#include <bits/stdc++.h> #define all(a) a.begin(), a.end() #define int long long #define PII pair<int, int> using ll = long long; const int N = 1e5 + 10, INF = 1e18, MOD = 1e9 + 7; using namespace std; void solve() { int n; cin >> n; vector<int> a(n), h(n, -1), ans(n); vector<vector<int>> front(n); for (int i = 0; i < n; i++) { cin >> a[i]; if (a[i]) front[a[i] - 1].push_back(i); } int high = n; auto dfs = [&](auto &&dfs, int u) -> int { for (auto it : front[u]) h[it] = dfs(dfs, it); return --high; }; for (int i = 0; i < n; i++) ans[h[i] = (h[i] == -1 ? dfs(dfs, i) : h[i])] = i + 1; for (int i = 0; i < n; i++) cout << ans[i] << ' '; } signed main() { ios::sync_with_stdio(0), cin.tie(0); int T = 1; // cin >> T, cin.get(); while (T--) solve(); return 0; }