首页 > 其他分享 >NC22494 选点

NC22494 选点

时间:2023-06-22 21:56:09浏览次数:44  
标签:选点 idx int NC22494 init 序列 节点

题目链接

题目

题目描述

有一棵n个节点的二叉树,1为根节点,每个节点有一个值wi。现在要选出尽量多的点。

对于任意一棵子树,都要满足:

如果选了根节点的话,在这棵子树内选的其他的点都要比根节点的值

如果在左子树选了一个点,在右子树中选的其他点要比它

输入描述

第一行一个整数n。第二行n个整数wi,表示每个点的权值。
接下来n行,每行两个整数a,b。第i+2行表示第i个节点的左右儿子节点。没有为0。
\(n,a,b\leq10^5, -2\times10^9\leq w_i \leq 2\times 10^9\)

输出描述

一行一个整数表示答案。

示例1

输入

5
1 5 4 2 3
3 2
4 5
0 0
0 0
0 0 

输出

3

题解

知识点:DFS序,线性dp,二分。

注意到,要求选点的大小是 \(root < right < left\) ,因此我们可以按照根右左的顺序处理出dfn序。这个序列将选点规则转化为,选取一个严格递增的一个子序列,问题就变为最长上升子序列。

我们还需要对最长上升子序列做一个优化,通常可以用权值树状数组或者在长度为下标的数组上二分,可以优化为线性对数复杂度,这里用的是后者,比较方便。

时间复杂度 \(O(n \log n)\)

空间复杂度 \(O(n)\)

代码

#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;
}

标签:选点,idx,int,NC22494,init,序列,节点
From: https://www.cnblogs.com/BlankYang/p/17498409.html

相关文章

  • 区间选点问题
    题目描述数轴上有\(n\)开区间\((a_i,b_i)\),请选择尽量多的区间,使其两两不相交。(开区间意味着,左右两个端点是不包含的)输入格式第一行\(n(n\le1000000)\),之后\(n\)行,每行两个数分别为\(ai,bi\),输出格式最少需要的点的个数样例样例输入13132435样例输出11数据范......
  • 区间选点
    #include<bits/stdc++.h>usingnamespacestd;constintN=1e5+10;intn;structRange{intl;intr;booloperator<(constRange&w)const{returnr<w.r;}}range[N];intmain(){intn;cin>>n;for(inti=0;i<......
  • AcWing905.区间选点
    题目详情知识点区间贪心为什么叫贪心呢?——短视,每次只是在看眼前的东西,在眼前的决策中选一个最优解。而贪心就是根据这种策略能够走到全局最优解的方法【如果用函数图像来表示就是一个单峰的图】贪心的普遍方案一般来说贪心问题没有思路的时候我们可以先随便试一下,再去举一......
  • 贪心(区间选点)
    #include<bits/stdc++.h>usingnamespacestd;constintN=1e5+10;intn;structRange{intl;intr;booloperator<(constRange&w)const{returnr<w.r;}}range[N];intmain(){intn;cin>>n;for(inti=0;i<......
  • 最新版人脸识别小程序 图片识别 生成码签到码 地图上选点进行位置签到 计算签到距离
    技术选型1,前端小程序原生MINA框架cssJavaScriptWxml2,管理后台云开发Cms内容管理系统web网页3,数据后台小程序云开发云函数云开发数据库(基于MongoDB)云存储4,人脸识别算法基于百度智能云实现人脸识别一,用户端效果图预览老规矩我们先来看效果图,如果效果图符合你的需求,就继续往下......
  • 区间选点(最大不相交区间数)
    区间选点:https://www.acwing.com/problem/content/907/最大不相交区间数:https://www.acwing.com/problem/content/910/题目描述给定N个闭区间[ai,bi],请你在数轴上选......