可持久化线段树的前置知识是权值线段树,但是你不学也没有太大的关系因为思想不是很难理解。


可持久化线段树支持历史记录查询,这是它赖以解题的方法。

在本题中思路是建立n颗线段树,然后对于每次询问,考虑其中两颗:由于这n颗线段树的结构都一样,而且区间是可以加减的,所以我们将它们相减,再搜一下就可以得到第K大了。


我们每一颗线段树,维护的是元素在区间中出现的次数。

假如直接建n颗树,空间不能接受,因此我们可以考虑简化。可以发现,这些区间都是[1,i]的形式,因此左半部分事实上都是相同的,每一次建立新的树我们只用右半部分新建,重复利用左半部分即可,这样的话空间就可以接受了。


重要变量

int a[N],b[N],T[N];
int sum[N*DEPTH],L[N*DEPTH],R[N*DEPTH];

a数组是题目给出的数组。

b数组是经过排序去重之后的数组。

T数组储存每一颗线段树的根节点(和普通线段树不一样,可持久化线段树的建树和更新都有返回值)。

sum数组就是区间中数的个数。

L和R表示左儿子与右儿子。


建树

inline int build(int l,int r){
    int pos=tot++,mid=(l+r)>>1;
    if(l<r){
        build(l,mid),build(mid+1,r);
    }
    return pos;
}

首先先新建节点,然后递归建树,没什么好讲的。

注意函数末尾返回新建节点的编号(用于T数组的赋值)。


更新

inline int update(int l,int r,int v,int pre){
    int pos=tot++,mid=(l+r)>>1;
    L[pos]=L[pre],R[pos]=R[pre],sum[pos]=sum[pre]+1;
    if(l<r){
        if(v<=mid)L[pos]=update(l,mid,v,L[pre]);
        else R[pos]=update(mid+1,r,v,R[pre]);
    }
    return pos;
}

和普通线段树的更新相比,可持久化线段树的少了一个pos表示当前位置,多了一个pre表示之前的。

首先还是先新建一个节点(毕竟我们可持久化就是一颗颗树),然后新的这一个部分先连向之前那个节点的左右儿子。

这个时候,我们再根据更新的值去重新确定新的左右儿子。

然后最后返回节点编号(为了顶上的确定流程)。


查询

inline int query(int phase1,int phase2,int l,int r,int k){
    int t=sum[L[phase2]]-sum[L[phase1]],mid=(l+r)>>1;
    if(l<r){
        if(k<=t)return query(L[phase1],L[phase2],l,mid,k);
        return query(R[phase1],R[phase2],mid+1,r,k-t);
    }
}

查询操作比较好理解,有点像差分。

就是我们有两个版本的线段树,然后拿他们相减,一路往下找,最后拿到答案即可。


然后就写完了。

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
namespace ElderTree{
    const qwq N=200200,DEPTH=23;
    inline qwq read(){
        qwq x=0,f=1;char c=getchar();
        for(;c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
        for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';
        return x*f;
    }
    qwq n,m,q,tot;
    qwq a[N],b[N],T[N];
    qwq sum[N*DEPTH],L[N*DEPTH],R[N*DEPTH];
    inline qwq build(qwq l,qwq r){
        qwq pos=tot++,mid=(l+r)>>1;
        if(l<r){
            build(l,mid),build(mid+1,r);
        }
        return pos;
    }
    inline qwq update(qwq l,qwq r,qwq v,qwq pre){
        qwq pos=tot++,mid=(l+r)>>1;
        L[pos]=L[pre],R[pos]=R[pre],sum[pos]=sum[pre]+1;
        if(l<r){
            if(v<=mid)L[pos]=update(l,mid,v,L[pre]);
            else R[pos]=update(mid+1,r,v,R[pre]);
        }
        return pos;
    }
    inline qwq query(qwq phase1,qwq phase2,qwq l,qwq r,qwq k){
        qwq t=sum[L[phase2]]-sum[L[phase1]],mid=(l+r)>>1;
        if(l<r){
            if(k<=t)return query(L[phase1],L[phase2],l,mid,k);
            return query(R[phase1],R[phase2],mid+1,r,k-t);
        }
    }
}
using namespace ElderTree;
qwq main(){
    n=read(),q=read();
    for(qwq i=1;i<=n;++i)a[i]=read(),b[i]=a[i];
    sort(b+1,b+n+1),m=unique(b+1,b+n+1)-1-b,T[0]=build(1,m);
    for(qwq i=1;i<=n;++i){
        qwq t=lower_bound(b+1,b+m+1,a[i])-b;
        T[i]=update(1,m,t,T[i-1]);
    }
    while(q--){
        qwq x,y,z;
        x=read(),y=read(),z=read();
        cout<<b[query(T[x-1],T[y],1,m,z)]<<endl;
    }
    return 0;
}

题解 P3834 【【模板】可持久化线段树 1(主席树)】的更多相关文章

  1. 洛谷P3834 [模板]可持久化线段树1(主席树) [主席树]

    题目传送门 可持久化线段树1(主席树) 题目背景 这是个非常经典的主席树入门题——静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个正整数构成的序列,将对于指定 ...

  2. P3919 【模板】可持久化数组 -初步探究主席树

    本篇blog主要是给自己(大家)看的. 感谢longlongzhu123奆佬(此人初二LCT)的指点,使本蒟蒻可以快速开始主席树入门. what is 主席树? $        $主席树这个名字只不 ...

  3. 归并树 划分树 可持久化线段树(主席树) 入门题 hdu 2665

    如果题目给出1e5的数据范围,,以前只会用n*log(n)的方法去想 今天学了一下两三种n*n*log(n)的数据结构 他们就是大名鼎鼎的 归并树 划分树 主席树,,,, 首先来说两个问题,,区间第k ...

  4. 【题解】BZOJ3489 A Hard RMQ problem(主席树套主席树)

    [题解]A simple RMQ problem 占坑,免得咕咕咕了,争取在2h内写出代码 upd:由于博主太菜而且硬是要用指针写两个主席树,所以延后2hQAQ upd:由于博主太菜而且太懒所以他决定 ...

  5. POJ 2104 K-th Number(分桶,线段树,主席树)

    一道比较经典的数据结构题.可以用多种方式来做. 一,分桶法(平方分解). 根据数字x的大小和区间内不大于x的数字数量cnt的单调性,可知第k大数kth对应的cnt应该满足cnt≥k, 且kth是满足条 ...

  6. 【BZOJ4771】七彩树(主席树)

    [BZOJ4771]七彩树(主席树) 题面 BZOJ 题解 如果没有深度限制,每次只询问子树内的颜色个数,除了树套树\(dfs\)序加前驱或者后继强行二维数点之外,还有这样一种做法: 把所有相同颜色的 ...

  7. 洛谷P3248 树 [HNOI2016] 主席树+倍增+分治

    正解:主席树+倍增+分治 解题报告: 传送门! 首先看到这题会想到之前考过的这题 但是那题其实简单一些,,,因为那题只要用个分治+预处理就好,只是有点儿思维难度而已 这题就不一样,因为它说了是按照原树 ...

  8. poj 2104 K-th Number 划分树,主席树讲解

    K-th Number Input The first line of the input file contains n --- the size of the array, and m --- t ...

  9. BZOJ_2588_Spoj 10628. Count on a tree_树剖+主席树

    BZOJ_2588_Spoj 10628. Count on a tree_树剖+主席树 题意: 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastan ...

  10. POJ 2761 Feed the dogs(平衡树or划分树or主席树)

    Description Wind loves pretty dogs very much, and she has n pet dogs. So Jiajia has to feed the dogs ...

随机推荐

  1. BZOJ 2314 士兵的放置(支配集)

    显然是\(DP\). 设\(dp[i][0/1/2]\)代表以i为根且\(i上有士兵放置/i被控制但i上没有士兵/i没有被控制\)的最小代价. \(g[i][0/1/2]\)代表对应的方案数. 然后运 ...

  2. 2019-03-21 Python Request InsecureRequestWarning

    问题: 使用Python3 requests发送HTTPS请求,已经关闭认证(verify=False)情况下,控制台会输出以下错误: InsecureRequestWarning: Unverifi ...

  3. poj 3311 Hie with the Pie (状压dp) (Tsp问题)

    这道题就是Tsp问题,稍微加了些改变 注意以下问题 (1)每个点可以经过多次,这里就可以用弗洛伊德初始化最短距离 (2)在循环中集合可以用S表示更清晰一些 (3)第一维为状态,第二维为在哪个点,不要写 ...

  4. Nginx 实现反向代理

    Nginx 实现反向代理 两个域名指向同一台 Nginx 服务器,用户访问不同的域名显示不同的网页内容 两个域名分别是 www.test1.com www.test2.com 1.准备工作 下载及安装 ...

  5. SQL SERVER-identity | @@identity | scope_identity

    主键自增 IDENTITY(1,1),MS SQL Server 使用 IDENTITY 关键字来执行 auto-increment 任务. 在上面的实例中,IDENTITY 的开始值是 1,每条新记 ...

  6. 洛谷 P3420 [POI2005]SKA-Piggy Banks

    P3420 [POI2005]SKA-Piggy Banks 题目描述 Byteazar the Dragon has NN piggy banks. Each piggy bank can eith ...

  7. [Angular] Set Metadata in HTTP Headers with Angular HttpHeaders

    Besides sending (or requesting) the actual data to the server API, there’s also often the need to se ...

  8. leveldb学习:sstable(2)

    block写入:block_builder block.h和.cc里定义了block的entry存储格式和restart,提供了entry的查找接口以及迭代器.那么怎样往写block里写entry呢? ...

  9. OpenGL ES 3.0 Graphics Pipeline

    一:OpenGL ES 3.0 Graphics Pipeline  渲染管道如下图 1.Vertex Buffer/Arrays Objects的数据由应用程序传进来 2.由上图可以看到Textur ...

  10. python部分

    读取骨骼数据相关的多个json,拼接到一起 # -- coding: utf-8 -- import os path = "./test" #文件夹目录 files= os.lis ...