zoukankan      html  css  js  c++  java
  • bzoj4919 [Lydsy1706月赛]大根堆

    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

    设f[i][j]表示i的子树内选择点集的权值最大值为j时最多选几个点,用启发式合并配合线段树转移即可。

    时间复杂度O(nlog2n)。

    观察转移可以得到如下等效的简单做法:当树退化成链时,其实就是求LIS一般情况下,对于每个点维护一个集合,每次将x点所有儿子的集合合并,然后用v去替换里面最小的比它大的数,最后根节点的集合大小就是答案。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cmath>
     5 #include<algorithm>
     6 using namespace std;
     7 struct Node
     8 {
     9     int next,to;
    10 }edge[400001];
    11 int num,head[200001],c[20000001],ch[20000001][2],flag,pos,root[200001],n,a[200001],b[200001];
    12 void add(int u,int v)
    13 {
    14     num++;
    15     edge[num].next=head[u];
    16     head[u]=num;
    17     edge[num].to=v;
    18 }
    19 void pushup(int rt)
    20 {
    21     c[rt]=c[ch[rt][0]]+c[ch[rt][1]];
    22 }
    23 int merge(int a,int b)
    24 {
    25     if (!a) return b;
    26     if (!b) return a;
    27     ch[a][0]=merge(ch[a][0],ch[b][0]);
    28     ch[a][1]=merge(ch[a][1],ch[b][1]);
    29     c[a]+=c[b];
    30     c[b]=0;
    31     return a;
    32 }
    33 void del(int rt,int l,int r)
    34 {
    35     if (l==r) 
    36     {
    37         c[rt]--;
    38         flag=0;
    39         return;
    40     }
    41     int mid=(l+r)/2;
    42     if (c[ch[rt][0]]) del(ch[rt][0],l,mid);
    43     else del(ch[rt][1],mid+1,r);
    44     pushup(rt);
    45 }
    46 void update(int &rt,int l,int r,int x)
    47 {
    48     if (!rt) rt=++pos;
    49     if (l==r)
    50     {
    51         if (c[rt]==0) c[rt]++,flag=1;
    52         return;
    53     }
    54     int mid=(l+r)/2;
    55     if (x<=mid) 
    56     {
    57         update(ch[rt][0],l,mid,x);
    58         if (flag&&c[ch[rt][1]]) del(ch[rt][1],mid+1,r);
    59     }
    60     else
    61     update(ch[rt][1],mid+1,r,x);
    62     pushup(rt);
    63 }
    64 void dfs(int x)
    65 {int i;
    66     for (i=head[x];i;i=edge[i].next)
    67     {
    68         int v=edge[i].to;
    69         dfs(v);
    70         root[x]=merge(root[x],root[v]);
    71     }
    72     flag=0;
    73     update(root[x],1,n,a[x]);
    74 }
    75 int main()
    76 {int i,pa,sz;
    77     cin>>n;
    78     for (i=1;i<=n;i++)
    79     {
    80         scanf("%d",&a[i]);
    81         b[i]=a[i];
    82         scanf("%d",&pa);
    83         if (pa)
    84         add(pa,i);
    85     }
    86     sort(b+1,b+n+1);
    87     sz=unique(b+1,b+n+1)-b-1;
    88     for (i=1;i<=n;i++)
    89     a[i]=lower_bound(b+1,b+sz+1,a[i])-b;
    90     dfs(1);
    91     cout<<c[root[1]];
    92 }
    93 
  • 相关阅读:
    maven
    sublime text
    ios category
    python
    activiti
    出版社
    gradle
    selenium
    spring
    Ansible状态管理
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8759810.html
Copyright © 2011-2022 走看看