Luogu P3834

可持久化数据结构就是支持在历史版本上进行查询和修改操作的数据结构。

主席树就是对线段树的改进,使之可持久化。

前置知识:动态开点线段树

我们利用权值(值域)线段树统计区间内的数出现的次数。

(权值线段树类似于线段树+桶)

那么我们可以对每一个位置建立一棵线段树,维护\(1\)~\(i\)的数据在一个区间上出现的次数。

求\(a[l...r]\)第k小,可以令第\(r\)棵线段树在区间\([x,y]\)上出现的次数减去上第\(l-1\)棵的线段树在区间\([x,y]\)上出现的次数,这样就可以得出\(a[l...r]\)在区间\([x,y]\)上出现的次数,如果次数小于\(k\),那么说明第\(k\)大在相邻的下一个区间。

事实上我们不可能对每个位置建立线段树,否则一定会MLE,所以对于这个版本相对于上一个版本没有改变过的节点,我们可以直接使用上一个版本的节点。

结合代码进行理解:

#include<cstdio>
#include<algorithm>
#define mid ((l+r)>>1)
using namespace std;
const int maxn=2e5;
int tot,tree[maxn<<5],ls[maxn<<5],rs[maxn<<5],n,m,a[maxn],b[maxn],rt[maxn],l,r,k;
//rt[]为各个版本的根节点,ls[]为节点的左儿子,rs[]为节点的右儿子
int build(int l,int r)
{
int now=++tot;
if (l==r)
{
tree[now]++;
return now;
}
ls[now]=build(l,mid);
rs[now]=build(mid+1,r);
return now;
}
int update(int root,int l,int r,int pnt)
{
int now=++tot;//新建节点
if (l<=pnt&&pnt<=r)
{
tree[now]=tree[root]+1;//继承信息
ls[now]=ls[root];
rs[now]=rs[root];
//记录左右儿子,假设可以直接使用上一个版本的节点
}
if (l==r) return now;
if (mid>=pnt) ls[now]=update(ls[now],l,mid,pnt);
else rs[now]=update(rs[now],mid+1,r,pnt);
//更新,并更换儿子节点编号
return now;
}
int query(int u,int v,int l,int r,int k)
{
if (l==r) return l;
int tmp=tree[ls[v]]-tree[ls[u]];//计算左区间出现次数
if (tmp>=k) return query(ls[u],ls[v],l,mid,k);
else return query(rs[u],rs[v],mid+1,r,k-tmp);//不在
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[i]=a[i];//保存副本供离散化使用
}
sort(b+1,b+1+n);
int newend=unique(b+1,b+1+n)-b-1;
rt[0]=build(1,newend);//首先建立一个空的线段树
for (int i=1;i<=n;i++)
{
int loc=lower_bound(b+1,b+1+newend,a[i])-b;
rt[i]=update(rt[i-1],1,newend,loc);//更新,记录新版本的根节点
}
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&l,&r,&k);
int loc=query(rt[l-1],rt[r],1,newend,k);
printf("%d\n",b[loc]);
}
return 0;
}

【Luogu P3834】可持久化线段树(主席树)的更多相关文章

  1. 线段树简单入门 (含普通线段树, zkw线段树, 主席树)

    线段树简单入门 递归版线段树 线段树的定义 线段树, 顾名思义, 就是每个节点表示一个区间. 线段树通常维护一些区间的值, 例如区间和. 比如, 上图 \([2, 5]\) 区间的和, 为以下区间的和 ...

  2. [Luogu 3701] 「伪模板」主席树

    [Luogu 3701] 「伪模板」主席树 这是一道网络流,不是主席树,不是什么数据结构,而是网络流. 题目背景及描述都非常的暴力,以至于 Capella 在做此题的过程中不禁感到生命流逝. S 向 ...

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

    题目:https://www.luogu.org/problemnew/show/P3834 无法忍受了,我要写主席树! 解决区间第 k 大查询问题,可以用主席树,像前缀和一样建立 n 棵前缀区间的权 ...

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

    主席树可以存储线段树的历史状态,空间消耗很大,一般开45n即可 #include <iostream> #include <cstdio> #include <cstri ...

  5. [学习笔记] 可持久化线段树&主席树

    众所周知,线段树是一个非常好用也好写的数据结构, 因此,我们今天的前置技能:线段树. 然而,可持久化到底是什么东西? 别急,我们一步一步来... step 1 首先,一道简化的模型: 给定一个长度为\ ...

  6. 权值线段树&&可持久化线段树&&主席树

    权值线段树 顾名思义,就是以权值为下标建立的线段树. 现在让我们来考虑考虑上面那句话的产生的三个小问题: 1. 如果说权值作为下标了,那这颗线段树里存什么呢? ----- 这颗线段树中, 记录每个值出 ...

  7. 【数据结构模版】可持久化线段树 && 主席树

    浙江集训Day4,从早8:00懵B到晚21:00,只搞懂了可持久化线段树以及主席树的板子.今天只能记个大概,以后详细完善讲解. 可持久化线段树指的是一种基于线段树的可回溯历史状态的数据结构.我们想要保 ...

  8. bzoj 4408: [Fjoi 2016]神秘数 数学 可持久化线段树 主席树

    https://www.lydsy.com/JudgeOnline/problem.php?id=4299 一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数.例如S={1,1,1 ...

  9. 牛客网 暑期ACM多校训练营(第一场)J.Different Integers-区间两侧不同数字的个数-离线树状数组 or 可持久化线段树(主席树)

    J.Different Integers 题意就是给你l,r,问你在区间两侧的[1,l]和[r,n]中,不同数的个数. 两种思路: 1.将数组长度扩大两倍,for(int i=n+1;i<=2* ...

  10. [POJ2104] K – th Number (可持久化线段树 主席树)

    题目背景 这是个非常经典的主席树入门题--静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个正整数构成的序列,将对于指定的闭区间查询其区间内的第K小值. 输入输 ...

随机推荐

  1. unity发布ios高通AR的问题

    1)缺少引用,无法找到vuforiaBehavior 原因:Windows下的工程,直接考到mac下,导致unity自带插件(2017)有问题 解决:首先在playerSettings-xrSetti ...

  2. UnityWebRequest_ZT

    using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using U ...

  3. js重点

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  4. Java多线程(十五):CountDownLatch,Semaphore,Exchanger,CyclicBarrier,Callable和Future

    CountDownLatch CountDownLatch用来使一个线程或多个线程等待到其他线程完成.CountDownLatch有个初始值count,await方法会阻塞线程,直到通过countDo ...

  5. Vue + Mui

    概述 Vue套用Mui的外壳开发app项目,可以通过Mui的 manifest.json 文件添加权限 1.新建Mui项目 首先,新建一个空的Mui项目 window.location.href = ...

  6. Topshelf+Quartz在.Net Core框架下的实现

    在我们日常开发工作中,经常会运用到Quartz+Topshelf组件的组合来开发一些定时任务.那么在.Net Core下如何去使用呢?我自己尝试搭建了一个测试项目,过程中遇到了以下一些问题: Quar ...

  7. find 小案例

    说明:前几天对生产环境的一些重要数据进行备份时用到了find,查找特定符合条件的文件名后拷贝至指定目录,但是只拷贝了部分匹配到的文件 小案例模拟还原: [root@centos- ~]# ll /te ...

  8. JavaSE常用API

    1.Math.round(11.5)等于多少?Math.round(-11.5)又等于多少? Math.round(11.5)的返回值是12,Math.round(-11.5)的返回值是-11.四舍五 ...

  9. HTML基本单词《结构化标签》

  10. C/c.pp:贪心,二分答案

    说是贪心有点牵强. 其次,答案满足单调性,如果在k次操作能完成那么在k+1次操作内也能完成. 因为大不了你就把多的一次对方操作再进行一次就好了. 怎么操作呢? 我们从头扫这个序列,遇到每一个不匹配位置 ...