选点(dfs+LIS)
选点
https://ac.nowcoder.com/acm/problem/22494
题目:
有一棵个节点的二叉树,
为根节点,每个节点有一个值
。现在要选出尽量多的点。
对于任意一棵子树,都要满足:
如果选了根节点的话,在这棵子树内选的其他的点都要比根节点的值大;
如果在左子树选了一个点,在右子树中选的其他点要比它小;
做法:
题意转化一下。“右子树中选的点要比左子树中选的点小”反一下就是“左子树中选的点要比右子树中选的点大”,而又有“若选根结点,子树内选的点要比根节点大”。
即我们选出的点有如下关系:根右子树
左子树。所以要最大化选点的数量,我们只需要后序遍历这棵树得到后序遍历序列,然后跑一个
(最长上升子序列)即可。复杂度
。
代码:
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define debug(a) cout << #a ": " << a << endl
using namespace std;
typedef long long ll;
const int N = 1e5 + 7;
int a[N], T[N][2], dfn[N], tag, te[N];
int dp[N], len;
void dfs(int u){
dfn[++tag] = a[u];
if (T[u][1]) dfs(T[u][1]);
if (T[u][0]) dfs(T[u][0]);
}
int main(void){
IOS;
int n;
while (cin >> n){
for (int i = 1; i <= n; ++i) cin >> a[i];
for (int i = 1; i <= n; ++i){
cin >> T[i][0] >> T[i][1];
}
tag = 0;
dfs(1);
len = 0;
for (int i = 1; i <= tag; ++i){
if (!len || dfn[i] > dp[len-1]) dp[len++] = dfn[i];
else dp[lower_bound(dp, dp+len, dfn[i])-dp] = dfn[i];
}
cout << len << endl;
}
return 0;
}
