BZOJ 4919 [Lydsy1706月赛]大根堆 (SRM08 T3)

【题解】

  求一个序列的LIS有一个二分做法是这样的:f[i]表示长度为i的上升序列中最后一个数最小可以是多少,每次二分大于等于当前数字x的f[j],把f[j]修改为x;如果找不到这样的f[j],那就把长度加一并记录新的f(即f[++len]=x)

  现在我们把这个做法放到树上,同样是可以做的。我们用set维护子树内的f数组,父节点在其孩子合并得到的set中二分第一个大于等于它的数字,换成父节点自己的值。合并子树的set直接启发式合并即可。两个log的复杂度。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<set>
 5 #define N 200010
 6 #define rg register
 7 #define LL long long
 8 using namespace std;
 9 int n,tot,last[N],val[N];
10 multiset<int>f[N];
11 struct edge{
12     int to,pre;
13 }e[N];
14 inline int read(){
15     int k=0,f=1; char c=getchar();
16     while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
17     while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar();
18     return k*f;
19 }
20 void dfs(int x,int fa){
21     for(rg int i=last[x],to;i;i=e[i].pre){
22         dfs(to=e[i].to,x);
23         if(f[to].size()>f[x].size()) swap(f[x],f[to]);
24         for(set<int>::iterator j=f[to].begin();j!=f[to].end();j++) f[x].insert(*j);
25         f[to].clear();
26     }
27     if(f[x].size()>0&&f[x].lower_bound(val[x])!=f[x].end()) f[x].erase(f[x].lower_bound(val[x]));
28     f[x].insert(val[x]);
29 }
30 int main(){
31     n=read();
32     for(rg int i=1;i<=n;i++){
33         val[i]=read(); int fa=read();
34         e[++tot]=(edge){i,last[fa]}; last[fa]=tot;
35     }
36     dfs(1,0);
37     printf("%d\n",f[1].size());
38     return 0;
39 }
View Code

 

posted @ 2018-09-27 16:57  Driver_Lao  阅读(144)  评论(0编辑  收藏  举报