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 }