Replay
Dup4:
- 厕所是个换换脑子的好地方?
- 要读题啊,不要别人不做,自己就跟着不做啊
X:
- 读题很重要啊!什么时候才能读对题 不演队友啊 D题看错题, 直到最后一小时才看懂
- 很多时候要看榜单做题
A:Aqours
Solved.
考虑一个点的子树下面有多少个叶子节点汇聚,
那么这个时候就可以更新某些叶子节点的答案
并且把距离该点最近的叶子节点返回上去继续做这一步操作
再正着 考虑除子树外 的离当前点最近的叶子节点的距离,用于更新子树中叶子结点的答案
相当于树形dp起手式
但是这里$n很大,不能DFS$
但是又注意到$i <= j 有 fa[i] < fa[j]$
相当于$bfs序列是1\;2\;\cdots n$
可以直接两次遍历来做这件事情
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 3000010 5 #define pii pair <int, int> 6 int n, fa[N], ans[N], d[N]; 7 vector <pii> G[N]; 8 pii g[N]; 9 10 int main() 11 { 12 while (scanf("%d", &n) != EOF) 13 { 14 for (int i = 1; i <= n; ++i) G[i].clear(); 15 memset(ans, -1, sizeof ans); 16 memset(d, 0, sizeof d); 17 fa[1] = 0; 18 for (int i = 2; i <= n; ++i) 19 { 20 scanf("%d", fa + i); 21 ++d[fa[i]]; 22 } 23 for (int v = n; v >= 1; --v) 24 { 25 int u = fa[v]; 26 if (!d[v]) 27 G[u].push_back(pii(v, 1)); 28 else 29 { 30 sort(G[v].begin(), G[v].end()); 31 pii tmp = *G[v].begin(); 32 ++tmp.second; 33 G[u].push_back(tmp); 34 int Min = (*G[v].begin()).second; 35 for (int i = 1, len = G[v].size(); i < len; ++i) 36 { 37 pii it = G[v][i]; 38 ans[it.first] = Min + it.second; 39 } 40 } 41 } 42 for (int v = 1; v <= n; ++v) 43 { 44 g[v] = pii(1e9, 1e9); 45 int u = fa[v]; 46 if (u) 47 { 48 g[v] = g[u]; 49 ++g[v].second; 50 pii tmp = g[v]; 51 if (tmp.first != -1) for (int i = 0, len = G[v].size(); i < len; ++i) 52 { 53 pii it = G[v][i]; 54 if (it.first > tmp.first) 55 ans[it.first] = min(ans[it.first], it.second + tmp.second); 56 } 57 } 58 if (!G[v].empty()) 59 { 60 pii it = *G[v].begin(); 61 if (it.second < g[v].second) 62 g[v] = it; 63 } 64 } 65 for (int i = 1; i <= n; ++i) if (!d[i]) printf("%d %d\n", i, ans[i]); 66 } 67 return 0; 68 }