链接:
https://ac.nowcoder.com/acm/contest/368/B
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
有一棵n个节点的二叉树,1为根节点,每个节点有一个值$w_i$。现在要选出尽量多的点。
对于任意一棵子树,都要满足:
如果选了根节点的话,在这棵子树内选的其他的点都要比根节点的值大;
如果在左子树选了一个点,在右子树中选的其他点要比它小。
输入描述:
第一行一个整数n。第二行n个整数$w_i$,表示每个点的权值。
接下来$n$行,每行两个整数$a,b$。第$i+2$行表示第$i$个节点的左右儿子节点。没有为$0$。
$n,a,b≤10^5,−2×10^9≤w_i≤2×10^9$
输出描述:
一行一个整数表示答案。
输入
1 2 3 4 5 6 7
| 5 1 5 4 2 3 3 2 4 5 0 0 0 0 0 0
|
输出
Solve
题目要求选出来的点满足:左儿子权值>右儿子权值>父亲权值。对二叉树进行后续遍历,可以得到左儿子->右儿子->父亲
的排列,然后对遍历得到的结果反向求LIS即可
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| #include <bits/stdc++.h> #define ll long long #define ull unsigned long long #define ms(a,b) memset(a,b,sizeof(a)) #define INF 0x7f7f7f7f const int maxn=1e5+10; const int mod=1e9+7; using namespace std; int w[maxn]; int arr[maxn]; int ar[maxn]; int dp[maxn]; struct wzy { int l,r; }p[maxn]; int cnt; void get_arr(int x) { if(p[x].l) get_arr(p[x].l); if(p[x].r) get_arr(p[x].r); arr[cnt++]=w[x]; } int main(int argc, char const *argv[]) { ios::sync_with_stdio(false); cin.tie(0); ms(p,0); int n,a,b; cin>>n; for(int i=1;i<=n;i++) cin>>w[i]; for(int i=1;i<=n;i++) { cin>>a>>b; p[i].l=a; p[i].r=b; } get_arr(1); for(int i=0;i<cnt;i++) ar[cnt-i-1]=arr[i]; int len=0; for(int i=0;i<n;i++) { int pos=upper_bound(dp,dp+len,ar[i])-dp; dp[pos]=ar[i]; len=max(len,pos+1); } cout<<len<<endl; return 0; }
|