题意
- n个结点的二叉树,1为根,每个结点有一个权值
- 要选择尽可能多的点,选点要满足如下要求
- 选了根那子树中的所有选择的点要比根更大
- 左子树选了一个点,右子树选的点要比他小
思路
- 对于选择规则,其实就是满足左结点>右结点>根
- 不妨维护根右左的dfn序,这样子找的就是dfn序中最长上升子序列
- LIS的朴素维护
,用二分优化使得复杂度变为 &preview=true)
- 二分优化方法
- 维护一个数组d[i]记录长为i的LIS的最小结尾
- 每新添一个元素,
lower_bound
找第一个大于等于它的
- 如果存在就替换掉它,扩充后面的空间
- 如果不存在说明,当前元素会构成新的LIS给d
push_back
当前元素
- 最后d[i]的size就是LIS的长度
lower_bound
找大于等的被替换,这样保证序列是严格单增的
upper_bound
找大于的被替换,这样保证序列是不下降的的
代码
#include<bits/stdc++.h>
using namespace std;
int v[202020];
struct ty{
int l,r;
}t[202020];
int tim;
int b[202020];
vector<int>d;
void dfs(int x){
b[++tim]=v[x];
if(t[x].r) dfs(t[x].r);
if(t[x].l) dfs(t[x].l);
}
int main(){
int n;
cin >> n;
for(int i=1;i<=n;i++){
cin >> v[i];
}
for(int i=1;i<=n;i++){
cin >> t[i].l >> t[i].r;
}
dfs(1);
for(int i=1;i<=n;i++){
auto p=lower_bound(d.begin(),d.end(),b[i]);
if(p==d.end()) d.push_back(b[i]);
else *p=b[i];
}
cout << d.size() << endl;
return 0;
}