[Knowledge Learning] Chairman tree

Two days learning the Chairman of the tree, the tree is basically get to know how to operate the chairman of


Chairman of the tree, is a kind of persistent segment tree. The simplest operation is to maintain a static Interval \ (k \) small

Chairman of the tree through the relevant operation and maintenance history versions for query interval


Chairman of the principle of the tree

Suppose now that there is such a sequence: \ (4,1,3,5,2 \)

Asked how determined interval [1,3] in the size of the second number?

With a large eye observation, it is clear that 3

So let the computer to how to achieve it?He has no eyes

For this sequence, we can start to build an empty weight segment tree, named "Tree 0" (easy to use back), as shown:

Do not tell me you do not know what is the right value segment tree of their own to Baidu;

Now there first sequence number is \ (4 \) , we insert into the tree inside a \ (4 \) , because you want to keep the version history, so we \ (4 \) Create a segment tree this number, name "tree 1", as shown:

Why is this so?

\ (. 1 \ Le. 4 \ LE5 \) , so that the interval [1,5] ++;

\ (. 4 \ Le. 4 \ LE5 \) , so that the interval [4,5] ++;

\ (. 4 \ Le. 4 \ LE4 \) , so that the interval [4,4] ++;

Other or \ (0 \) ;

Do not you see. . .

Further inserted second number \ (1 \) , into a "tree 2", not explained here

And then inserted into the third number \ (3 \) , into a "tree 3"

OK! Now we can already find the size of [1,3] is the second largest in the number of

Recursive queries will be ranked right?

Do not look at this:

  • 进入[1,5]节点,我们发现他的左儿子的子树个数为\(2\) , $2\le k $ \((k=2)\),于是进入[1,3]节点;

  • 然后我们发现[1,3]节点的左儿子子树个数\(1 < k\) \((k=2)\),于是进入[3,3]节点;

  • 此时我们把\(k\)更新为\(1\) (\(2-1=1\));

  • 走到头了,于是就返回3,所以答案就是3,也就是原来的序列区间[1, 3]的第2小就是3

现在你明白了主席树是怎么操作了的吧?


疑问

但是有一个问题:上面我们求的是区间[1,3]的第 \(k\) 大的数

同理,区间[1,r] (\(r \in [1,n],r \in N\))的第 \(k\) 大数我们也就会求了

那怎么求区间[l,r]的第 \(k\) 大数呢?

举个例子,求区间[2,3]的第 \(k\) 大数

我们拿建出来的“树3”减掉“树1”后,再进行如上操作就可以了

这也就是前缀和思想

所以对于区间[l,r] 我们拿“树r”减去“树(l-1)”,再query一下就可以求得答案了


例题与代码

那么主席树就介绍完了,具体实现给个例题让大家看看,还有不懂得可以再参考一下他人的博客

例题:静态区间第 \(k\) 小(【模板】可持久化线段树1/主席树)

题目链接

(鸣谢@wsk1202提供板子)

#include <bits/stdc++.h>
#define N (200000+5)
#define ls ch[rt][0]
#define rs ch[rt][1]
#define vl ch[vs][0]
#define vr ch[vs][1]//几个宏定义
using namespace std;
int n,m,q;
int rt[N],ch[N<<5][2],tot,val[N<<5];
int a[N],b[N];
inline int query(int x){//离散化
    return lower_bound(b+1,b+m+1,x)-b;
}
inline void update(int &rt,int vs,int l,int r,int k){//新建一棵树
    rt=++tot;
    ls=vl,rs=vr;
    val[rt]=val[vs]+1;
    if(l==r) return;
    int mid=(l+r)>>1;
    if(k<=mid) update(ls,vl,l,mid,k);
    else update(rs,vr,mid+1,r,k);
}
inline int query(int rt,int vs,int l,int r,int k){//询问
    if(l==r) return l;
    int mid=(l+r)>>1;
    int v=val[vl]-val[ls];
    if(k<=v) return query(ls,vl,l,mid,k);
    else return query(rs,vr,mid+1,r,k-v);
}
int main(){
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
    sort(b+1,b+n+1);
    m=unique(b+1,b+n+1)-b-1;
    for(int i=1;i<=n;i++){
        update(rt[i],rt[i-1],1,n,query(a[i]));
    }
    while(q--){
        int l,r,k;
        scanf("%d%d%d",&l,&r,&k);
        printf("%d\n",b[query(rt[l-1],rt[r],1,n,k)]);
    }
    return 0;
}

Guess you like

Origin www.cnblogs.com/Xx-queue/p/12208581.html