主席树节点中维护的值,是([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)]//查询