静态主席树 P3834 【模板】可持久化线段树 1

再写一篇关于主席树的博客,也是最近学的,蒟蒻

主席树听起来非常高大上,实际上?也非常的高大上

至于为什么叫这个东西不讨论嘤嘤嘤
主席树我感觉就是一颗版本树,可以找到(以前的版本的树)的树
并且最大可能的重复利用上一个版本的树的节点来构建新的树
主席树又叫做可持久化线段树
是一个权值线段树。
P3834 【模板】可持久化线段树 1(主席树)

题目描述
如题,给定N个整数构成的序列,将对于指定的闭区间查询其区间内的第K小值。

输入格式
第一行包含两个正整数N、M,分别表示序列的长度和查询的个数。

第二行包含N个整数,表示这个序列各项的数字。

接下来M行每行包含三个整数 l, r, kl,r,k , 表示查询区间[l, r][l,r]内的第k小值。

输出格式
输出包含k行,每行1个整数,依次表示每一次查询的结果

输入输出样例
输入 #1 复制
5 5
25957 6405 15770 26287 26465 
2 2 1
3 4 1
4 5 1
1 2 2
4 4 1
输出 #1 复制
6405
15770
26287
25957
26287

做这个题最重要的一句话:
第i个版本的树
某个节点node[k]所管理区间为[l,r]
该节点的权值表示的是,从a[1] 到 a[i]这i个数中 有 node[k].sum个数的大小排在所有数的[l,r]位

  • 步骤1 :首先先将数据去重离散化
  • 步骤2:建立空树
  • 步骤3:依次向树里面添加 index(第i 个数的排名)

在这里插入图片描述在这里插入图片描述

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>

#define inf 200010
struct Node
{
    int l_son,r_son,sum;
}node[inf*20];
int root[inf];

int n,m,q,tot = 0;
int a[inf],b[inf];
using namespace std;

int build(int,int);
int update(int,int,int,int);
int query(int,int,int,int,int);
int main()
{
    //   int T;scanf("%d",&T);
    // while(T--)
    {
        tot = 0;
        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);
        //cout<<m;
        root[0] = build(1,m);//空树的节点root[0]
        for(int i = 1; i <= n; i++)
        {
            int index = lower_bound(b+1,b+m+1,a[i]) - b;
            //  cout<<index<<endl;
            root[i] = update(root[i-1],1,m,index);
        }
        while(q--)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            int p = query(root[x-1],root[y],1,m,z);
            printf("%d\n",b[p]);
        }
    }
}
int query(int u,int v,int l,int r,int k)
{
    if(l == r) return l ;
    int mid = (l+r) >> 1;
    int x = node[node[v].l_son].sum - node[node[u].l_son].sum;
    if(x >= k) return query(node[u].l_son,node[v].l_son,l,mid,k);
    else query(node[u].r_son,node[v].r_son,mid+1,r,k-x);
}
int update(int last_father,int l,int r,int x)
{
#define  lf last_father

    int rt = ++tot;
    node[rt].l_son = node[lf].l_son;
    node[rt].r_son = node[lf].r_son;
    node[rt].sum = node[lf].sum + 1;
    if(l < r)
    {
        int mid = (l+r)>>1;
        if(x <= mid){
            node[rt].l_son = update(node[rt].l_son,l,mid,x);
        } else
            node[rt].r_son = update(node[rt].r_son,mid+1,r,x);
    }
    return rt;
}
inline int build(int l,int r)
{
    int rt = ++tot;
    if(l < r)
    {
        int mid = (l+r) >> 1;
        node[rt].l_son = build(l,mid);
        node[rt].r_son = build(mid+1,r);
    }
    return rt;
}

猜你喜欢

转载自blog.csdn.net/weixin_43912833/article/details/98659521