[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]大根堆的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ4919[Lydsy六月月赛]大根堆 线段树合并

[BZOJ4919]大根堆

[bzoj4919]大根堆

bzoj 4919: [Lydsy六月月赛]大根堆

BZOJ4919[Lydsy1706月赛]大根堆-------------线段树进阶

BZOJ4919[Lydsy六月月赛]大根堆