F 选点 前序遍历dfn序+dp求最长上升子序列 根<右子树<左子树选的点

链接:https://ac.nowcoder.com/acm/problem/22494
来源:牛客网

题目描述

有一棵n个节点的二叉树,1为根节点,每个节点有一个值wi。现在要选出尽量多的点。
对于任意一棵子树,都要满足:
如果选了根节点的话,在这棵子树内选的其他的点都要比根节点的值
如果在左子树选了一个点,在右子树中选的其他点要比它

输入描述:

第一行一个整数n。

第二行n个整数wi,表示每个点的权值。

接下来n行,每行两个整数a,b。第i+2行表示第i个节点的左右儿子节点。没有为0。
n,a,b≤105,−2×109≤wi≤2×109n,a,b\leq10^5, -2\times10^9\leq w_i \leq 2\times 10^9n,a,b105,2×109wi2×109

输出描述:

一行一个整数表示答案。
示例1

输入

复制
5
1 5 4 2 3
3 2
4 5
0 0
0 0
0 0 

输出

复制
3

分析:

按照根右左的顺序将所有值提取到一个数组里,

然后求这个数组的最长上升子序列就可以了

//-------------------------代码----------------------------

#define int ll
const int N = 5e5+10;
int n,m;

struct node {
    ll l,r;
} p[N];

ll a[N],dp[N],b[N],num = 0,len = 0;

void dfs(ll x) {
    if(!x) return;
    b[++num] = a[x];
    dfs(p[x].r);
    dfs(p[x].l);
}

void solve()
{
//    cin>>n>>m;
    cin>>n;
    fo(i,1,n) {
        cin>>a[i];
    }
    fo(i,1,n) {
        cin>>p[i].l>>p[i].r;
    }
    dfs(1);
    dp[++len] = b[1];
    fo(i,2,num) {
        if(b[i] > dp[len]) dp[++len] = b[i];
        else {
            auto t = upper_bound(dp+1, dp+1+len, b[i]) - dp;
            dp[t] = b[i];
        }
    }
//     cout<<endl;
    cout<<len<<endl;
}
void main_init() {}
signed main(){
    AC();clapping();TLE;
    cout<<fixed<<setprecision(12);
    main_init();
//  while(cin>>n,n)
//  while(cin>>n>>m,n,m)
//    int t;cin>>t;while(t -- )
    solve();
//    {solve(); }
    return 0;
}

/*样例区


*/

//------------------------------------------------------------

 

posted @ 2022-09-02 14:56  er007  阅读(25)  评论(0)    收藏  举报