[BZOJ4919]大根堆
Posted jefflyy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ4919]大根堆相关的知识,希望对你有一定的参考价值。
回忆一下序列LIS,$f_i$表示长度为$i$的LIS的最大数最小是多少,每次找到$f_{1\cdots i-1}$中第一个$\geq a_i$的位置并用$a_i$更新它
搬到树上是差不多的,我们用multiset维护每个子树内的DP值,因为子树之间互不影响所以可以直接合并multiset,最后再用根去更新multiset
感觉挺久没打treap所以练练手,1A海星
#include<stdio.h> #include<stdlib.h> int l[400010],r[400010],fix[400010],v[400010],siz[400010],M; void pushup(int x){siz[x]=siz[l[x]]+siz[r[x]]+1;} struct pr{ int l,r; pr(int a=0,int b=0){l=a;r=b;} }; pr splitk(int x,int k){ if(x==0)return pr(); pr s; if(k<=siz[l[x]]){ s=splitk(l[x],k); l[x]=s.r; s.r=x; }else{ s=splitk(r[x],k-siz[l[x]]-1); r[x]=s.l; s.l=x; } pushup(x); return s; } pr splitv(int x,int d){ if(x==0)return pr(); pr s; if(d<v[x]){ s=splitv(l[x],d); l[x]=s.r; s.r=x; }else{ s=splitv(r[x],d); r[x]=s.l; s.l=x; } pushup(x); return s; } void swap(int&a,int&b){a^=b^=a^=b;} int merge(int x,int y){ if(x==0)return y; if(y==0)return x; if(fix[x]>fix[y])swap(x,y); pr s=splitv(y,v[x]); l[x]=merge(l[x],s.l); r[x]=merge(r[x],s.r); pushup(x); return x; } int insert(int x,int d){ M++; fix[M]=rand(); v[M]=d; siz[M]=1; pr s=splitv(x,d); return merge(merge(s.l,M),s.r); } int erase(int x,int d){ pr s=splitv(x,d-1); return merge(s.l,splitk(s.r,1).r); } int h[200010],nex[200010],to[200010],val[200010]; void add(int a,int b){ M++; to[M]=b; nex[M]=h[a]; h[a]=M; } int rt[200010]; void dfs(int x){ for(int i=h[x];i;i=nex[i]){ dfs(to[i]); rt[x]=merge(rt[x],rt[to[i]]); } rt[x]=erase(rt[x],val[x]); rt[x]=insert(rt[x],val[x]); } int main(){ srand(19260817); int n,i,x,r; scanf("%d",&n); for(i=1;i<=n;i++){ scanf("%d%d",val+i,&x); if(x) add(x,i); else r=i; } M=0; dfs(r); printf("%d",siz[rt[r]]); }
以上是关于[BZOJ4919]大根堆的主要内容,如果未能解决你的问题,请参考以下文章