主席树模板

Posted tyner

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了主席树模板相关的知识,希望对你有一定的参考价值。

引入

首先请求出:

? 长度为n的序列

? m次询问全局第k小

做法:

? 画一棵(权值)线段树手动模拟,请记住此过程

之后,请思考;

? 长度为n的序列

? m次询问区间[l, r]中第k小值

? 值域 ±1e9

? n≤2e5 , m≤2e5

做法: 可持久化线段树

原理

用 [1, r]建得的线段树 - [1, l-1]建得的线段树 (即把这两颗形状一样的线段树上的每个节点的权值相减), 得到的即为区间[l, r]建得的线段树, 这样之后,我们就可以求出(这棵线段树)全局第k小值,而这个值也就是区间[l, r]的第k小值

代码实现

#include<cstdio>
#include<algorithm>
using namespace std;
#define MAX 200000+99

int n, m;

struct da

    int n,a,k;//输入顺序n,原数据a,离散化之后数据k 
a[MAX];
int ys[MAX];//da数组和原数的映射关系 

bool cmp1(da x, da xxx) 
    return x.a < xxx.a ;//用于离散化 

bool cmp2(da x, da xxx) 
    return x.n < xxx.n ;


int root[MAX];//保存森林中的各个根节点 //时间戳? 
int nodecnt;//所有节点的数量 
struct tree
    int sum;
    int lson, rson;
tr[MAX<<5];//2n+nlogn

int build(int l, int r) //建空树 
    int now = ++nodecnt;//加点 
    if(l == r) return now;
    int mid = (l+r)>>1;
    tr[now].lson = build(l, mid);
    tr[now].rson = build(mid+1, r);
    return now;


int insert(int last, int l, int r, int x) //建权值线段树 
    int now = ++nodecnt;
    tr[now].sum = tr[last].sum + 1;
    tr[now].lson = tr[last].lson , tr[now].rson = tr[last].rson;//先继承上一棵树再说
    if(l == r) return now;
    int mid =  (l+r)>>1;
    if(x <= mid) tr[now].lson = insert(tr[last].lson , l, mid, x);
    else tr[now].rson = insert(tr[last].rson , mid+1, r, x);
    return now;



int query(int ltree, int rtree, int l, int r, int k) //同时跳 
    if(l == r) return l;
    int mid = (l+r)>>1;
    int tmp = tr[tr[rtree].lson ].sum - tr[tr[ltree].lson ].sum ;
    if(tmp >= k) return query(tr[ltree].lson , tr[rtree].lson , l, mid, k);
    else return query(tr[ltree].rson , tr[rtree].rson , mid+1, r, k-tmp);



int main() 
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= n; i++) scanf("%d",&a[i].a ), a[i].n = i;
    sort(a+1, a+1+n, cmp1);
    int tot = 0;
    for(int i = 1; i <= n; i++) 
        a[i].k = ++tot;
        ys[tot] = a[i].a ;
        while(a[i+1].a == a[i].a) a[++i].k = tot;
    
    sort(a+1, a+1+n, cmp2);
//  for(int i = 1; i <= n; i++) printf("\n lsh : %d\n",a[i].k );
    root[0] = build(1,n);
    for(int i = 1;i <= n; i++)//边加点边建树 
        root[i] = insert(root[i-1], 1, n, a[i].k) ; 
    int ans, l, r, k; 
    for(int i = 1; i <= m; i++) 
        scanf("%d%d%d", &l, &r, &k);
        ans = query(root[l-1], root[r], 1, n, k);
        printf("%d\n", ys[ans]);
    

以上是关于主席树模板的主要内容,如果未能解决你的问题,请参考以下文章

模板可持久化线段树 1(主席树)

P3701 「伪模板」主席树

Yangk's 静态主席树-模板

主席树模板

模板主席树

P3834 模板可持久化线段树 1(主席树)