• [BZOJ4919][Lydsy1706月赛]大根堆


    4919: [Lydsy1706月赛]大根堆

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 591  Solved: 256
    [Submit][Status][Discuss]

    Description

    给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点。每个点有一个权值v_i。
    你需要将这棵树转化成一个大根堆。确切地说,你需要选择尽可能多的节点,满足大根堆的性质:对于任意两个点i,j,如果i在树上是j的祖先,那么v_i>v_j。
    请计算可选的最多的点数,注意这些点不必形成这棵树的一个连通子树。

    Input

    第一行包含一个正整数n(1<=n<=200000),表示节点的个数。
    接下来n行,每行两个整数v_i,p_i(0<=v_i<=10^9,1<=p_i<i,p_1=0),表示每个节点的权值与父亲。

    Output

    输出一行一个正整数,即最多的点数。

    Sample Input

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

    Sample Output

    5

    HINT

    Source

    [Submit][Status][Discuss]

    容易想出f[i][j]表示节点i的子树,最大值为j,最多能选几个点。

    DP方程显然,可以线段树区间修改优化,不同子树间要进行带标记线段树启发式合并,这就很麻烦了。

    重新考虑这个问题,容易发现如果是一条链的话实际上就是在问LIS,思考如何搬到树上。

    LIS的经典二分做法是:f[i]表示到当前为止长度为i的LIS末尾最大为多少,每次二分更新一个位置,而最大的非零f位置就是到当前为止的LIS长度。

    这个东西也可以用set维护,当前的size()就是LIS长度,这样就可以搬到树上了,两个子树启发式合并即可,十分巧妙。

     1 #include<set>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=l; i<=r; i++)
     5 using namespace std;
     6 
     7 const int N=200010;
     8 int n,cnt,x,h[N],a[N],to[N<<1],nxt[N<<1];
     9 multiset<int>f[N];
    10 
    11 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
    12 void dfs(int x,int fa){
    13     for (int i=h[x],k; i; i=nxt[i]) if ((k=to[i])!=fa){
    14         dfs(k,x); if (f[k].size()>f[x].size()) swap(f[x],f[k]);
    15         for (set<int>::iterator j=f[k].begin(); j!=f[k].end(); j++) f[x].insert(*j);
    16         f[k].clear();
    17     }
    18     if (f[x].size()>0 && f[x].lower_bound(a[x])!=f[x].end()) f[x].erase(f[x].lower_bound(a[x]));
    19     f[x].insert(a[x]);
    20 }
    21 
    22 int main(){
    23     freopen("bzoj4919.in","r",stdin);
    24     freopen("bzoj4919.out","w",stdout);
    25     scanf("%d%d%d",&n,&a[1],&x);
    26     rep(i,2,n) scanf("%d%d",&a[i],&x),add(x,i),add(i,x);
    27     dfs(1,0); printf("%d
    ",(int)f[1].size());
    28     return 0;
    29 }
  • 相关阅读:
    arm单板上移植gdb
    video on web
    chromium源码阅读
    CE-HTML简介
    multi-tap
    DPDK 网卡RSS(receive side scaling)简介
    c语言实现带LRU机制的哈希表
    Linux TCP协议使用的变量
    scp源码浅析
    Linux e1000e网卡驱动
  • 原文地址:https://www.cnblogs.com/HocRiser/p/8970601.html
Copyright © 2020-2023  润新知