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

Posted hsez-cyx

tags:

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

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

(本人的模板)

Description

题目背景

这是个非常经典的主席树入门题——静态区间第 kk 小数据已经过加强,请使用主席树。同时请注意常数优化

题目描述

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

输入格式

第一行包含两个正整数 n,mn,m,分别表示序列的长度和查询的个数。第二行包含 nn 个整数,表示这个序列各项的数字。接下来 mm 行每行包含三个整数 l, r, kl,r,k , 表示查询区间 [l, r][l,r] 内的第 kk 小值。

输出格式

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

Code

#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int N=2e5+10;
struct node
{
    int lc,rc,sum;
}f[N*40];
struct mode
{
    int v,id;
    bool operator <(const mode &o)const
    {
        return v<o.v;
    }
}a[N];
int n,m,rt[N],d[N],l,r,k,tot,cnt,re[N];
void build(int l,int r,int &x,int y,int pos)
{
    x=++tot;
    f[x]=f[y],f[x].sum++;
    if(l==r) return ;
    int mid=(l+r)>>1;
    if(pos<=mid) build(l,mid,f[x].lc,f[y].lc,pos);
    else build(mid+1,r,f[x].rc,f[y].rc,pos);
}
int ans(int l,int r,int x,int y,int k)
{
    if(l>=r) return l;
    int cnt=f[f[x].lc].sum-f[f[y].lc].sum;
    int mid=(l+r)>>1;
    if(cnt>=k) return ans(l,mid,f[x].lc,f[y].lc,k);
    else return ans(mid+1,r,f[x].rc,f[y].rc,k-cnt);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i].v),a[i].id=i;
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++)
    {
        if(i==1 || a[i].v!=a[i-1].v) re[++cnt]=a[i].v;
        d[a[i].id]=cnt;
    }
    for(int i=1;i<=n;i++) build(1,n,rt[i],rt[i-1],d[i]);
    while(m--)
    {
        scanf("%d%d%d",&l,&r,&k);
        printf("%d
",re[ans(1,n,rt[r],rt[l-1],k)]);
    }
    return 0;
}

 

以上是关于可持久化线段树 1(主席树模板)的主要内容,如果未能解决你的问题,请参考以下文章

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

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

解题报告:P3834 模板可持久化线段树 2(主席树)详解

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

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

可持久化线段树(主席树)