NC22494 选点
题目
题目描述
有一棵n个节点的二叉树,1为根节点,每个节点有一个值wi。现在要选出尽量多的点。
对于任意一棵子树,都要满足:
如果选了根节点的话,在这棵子树内选的其他的点都要比根节点的值大;
如果在左子树选了一个点,在右子树中选的其他点要比它小。
输入描述
第一行一个整数n。第二行n个整数wi,表示每个点的权值。
接下来n行,每行两个整数a,b。第i+2行表示第i个节点的左右儿子节点。没有为0。
输出描述
一行一个整数表示答案。
示例1
输入
5 1 5 4 2 3 3 2 4 5 0 0 0 0 0 0
输出
3
题解
知识点:DFS序,线性dp,二分。
注意到,要求选点的大小是 ,因此我们可以按照根右左的顺序处理出dfn序。这个序列将选点规则转化为,选取一个严格递增的一个子序列,问题就变为最长上升子序列。
我们还需要对最长上升子序列做一个优化,通常可以用权值树状数组或者在长度为下标的数组上二分,可以优化为线性对数复杂度,这里用的是后者,比较方便。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> using namespace std; using ll = long long; struct Graph { struct edge { int v, nxt; }; int idx; vector<int> h; vector<edge> e; Graph(int n = 0, int m = 0) { init(n, m); } void init(int n, int m) { idx = 0; h.assign(n + 1, 0); e.assign(m + 1, {}); } void add(int u, int v) { e[++idx] = { v,h[u] }; h[u] = idx; } }; const int N = 100007; Graph g; int a[N]; int dfncnt; int dfn[N]; void dfs(int u) { dfn[++dfncnt] = u; for (int i = g.h[u];i;i = g.e[i].nxt) { int v = g.e[i].v; dfs(v); } } int lst[N];//! 长度为i的上升子序列的最小结尾 int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n; cin >> n; g.init(n, n << 1); for (int i = 1;i <= n;i++) cin >> a[i]; for (int i = 1;i <= n;i++) { int l, r; cin >> l >> r; if (l) g.add(i, l); if (r) g.add(i, r); } dfs(1); int ans = 0; for (int i = 1;i <= n;i++) { int pos = upper_bound(lst + 1, lst + ans + 1, a[dfn[i]]) - lst;//! 注意有效长度是ans,多了会错乱 lst[pos] = a[dfn[i]]; ans = max(ans, pos); } cout << ans << '\n'; return 0; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/17498409.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
2022-06-22 NC15163 逆序数
2022-06-22 NC207028 第k小数
2022-06-22 NC15979 小q的数列