主席树

主席树

主席树是一种可持久化数据结构(可持久化线段树)。

当要用到多个线段树时我们可以用主席树,主席树的各个节点都是同一结构的线段树。

对于一般的线段树来说,如果父节点的编号是 i ,那么他的两个子节点的编号分别为 2 * i(左),  2 * i + 1(右),但是主席树在这一点则有别于一般的线段树,每一个父节点,他的两个子节点的编号则不一定满足这个关系。

我们要处理的数可能会很大需要离散化。

 

参考博客:

https://blog.csdn.net/weixin_42165981/article/details/81131661

https://blog.csdn.net/metalseed/article/details/8045038

 

 

 

查询区间第k大板子

 

#include <cmath>
#include <cstdio>
#include <vector>
#include <algorithm>
#define ll long long
using namespace std;
const int N = 2e5 + 10;
const int INF = 0x3f3f3f3f;
struct node{
    int l,r,sum;
}T[N*40];
vector<int> v;
int root[N],a[N],cnt=0;
// 单点更新 x为更新的 y为更新前的
void update(int l,int r,int &x,int y,int pos) {
    T[++cnt] = T[y],T[cnt].sum++,x = cnt;
    if (l==r) return;
    int mid = (l+r) >> 1;
    if (mid >= pos) update(l,mid,T[x].l,T[y].l,pos);
    else update(mid+1,r,T[x].r,T[y].r,pos);
}
// 查询[l,r]区间 x是l棵树 y是r棵树 求第k大
int query(int l, int r,int x,int y,int k) {
    if (l == r) return l;
    int mid = (l+r)>>1;
    int sum = T[T[y].l].sum - T[T[x].l].sum;
    if(sum >= k) return query(l,mid,T[x].l,T[y].l,k);
    else return query(mid+1,r,T[x].r,T[y].r,k-sum);
}

int main() {
    int n,m;
    scanf("%d%d",&n,&m);
    for (int i = 1; i <= n; i++) {
        scanf("%d",&a[i]);
        v.push_back(a[i]);
    }
    // 离散化
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
    for (int i = 1; i <= n; i++) {
        a[i] = lower_bound(v.begin(),v.end(),a[i])-v.begin() + 1;
        update(1,n,root[i],root[i-1],a[i]);
    }
    int l,r,k;
    while(m--) {
        scanf("%d%d%d",&l,&r,&k);
        printf("%d\n", v[query(1,n,root[l-1],root[r],k)-1]);
    }
    return 0;
}

 

posted @ 2019-08-01 18:08  19呀  阅读(176)  评论(0编辑  收藏  举报