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 

 

posted @ 2018-04-09 14:51  Z-Y-Y-S  阅读(431)  评论(0编辑  收藏  举报