主席树

主席树节点中维护的值,是\([x,y]\)之间这个区间内数字出现了的次数

利用可持久化线段树的性质来进行查询,如查询区间\([2,5]\),即将版本五和版本一对应节点相减,即为\([2, 5]\)内某个范围内的数字的个数

对于一个区间\([l, r]\),每次算出在\([l, mid]\)范围内的数字个数,如果数量$ \geqslant k \((\)k\(就是第\)k$小),就去查询左子树,否则就去查询右子树

\(code :\)

void build(int L,int R,int &cur)
{
	cur=++tree_cnt;
	if(L==R) return;
	int mid=(L+R)>>1;
	build(L,mid,ls[cur]);
	build(mid+1,R,rs[cur]);
}
void modify(int L,int R,int pos,int pre,int &cur)
{
	cur=++tree_cnt;
	ls[cur]=ls[pre],rs[cur]=rs[pre];
	val[cur]=val[pre]+1;
	if(L==R) return;
	int mid=(L+R)>>1;
	if(pos<=mid) modify(L,mid,pos,ls[pre],ls[cur]);
	if(pos>mid) modify(mid+1,R,pos,rs[pre],rs[cur]);
}
int query(int L,int R,int x,int y,int rnk)
{
	if(L==R) return L;
	int num=val[ls[y]]-val[ls[x]],mid=(L+R)>>1;
	if(num>=rnk) return query(L,mid,ls[x],ls[y],rnk);
	else return query(mid+1,R,rs[x],rs[y],rnk-num);
}

......

build(1,n,root[0]);
for(int i=1;i<=n;++i) modify(1,n,a[i],root[i-1],root[i]);//建树

rev[query(1,n,root[l-1],root[r],k)]//查询
posted @ 2020-01-22 20:25  lhm_liu  阅读(184)  评论(0编辑  收藏  举报