权值线段树、主席树学习

权值线段树总结 权值线段总结 权值线段树就是把线段树的每个点权,赋予一定的含义,比如数字出现的次数,数值前缀出现的次数,并用区间求和维护一个前缀信息,比如数字出现的次数,第K大等(不能实现区间第K大),前缀第K大等。 权值线段树优点: 能够比较容易实现平衡树的一系列操作 一个序列中,插入一个数,删除一个数,求值为数的排名,查询第K小的数,求比这个数小的数,求比这个数大的数。 上述操作都可以通过... 阅读详情

初学主席树,主要是反复看了卿学姐的视频(我竟然在B站学算法)和知乎“主席树是如何求区间k大的”,才算懂了点皮毛。

传送门:

卿学姐的B站视频

知乎-“主席树是如何求区间k大的”

首先,学习主席树要点的前置技能是权值线段树(卿学姐说的是线段树,个人认为不太确切)。权值线段树之所以会带上“权值”二字,是因为它是记录权值的线段树。因此需要用到离散化操作来处理a[1-n]。记录权值指的是,每个点上存的是区间内的数字出现的总次数。比如一个长度为10的数组[1,1,2,3,3,4,4,4,4,5]。

其中1出现了两次,那么[1,1]这个节点的值为2,2出现了1次,那么[2,2]这个节点的值为1,那么显然[1,2]这个节点的值为3,即1出现的次数和2出现的次数加和。那么如果我想要知道这个数组上的第k小,我就可以在这棵权值线段树上用logn的时间来实现。比如我想要求这个区间上的第7小,那么我先找到这棵树的根节点,根节点上的数字显示的是10,表示在[1,8]这个区间上一共有10个数字,那么我只要去看它的左孩子上的个数是多少。这时我看到左孩子上的数字是9,说明前9小的数字都在左子树上,那么我要找的第7小也在左子树上,那么我就递归去找左子树。当我再看左孩子的时候,看到数字是3,说明前3小的数字在左子树上,那么我要找的就是右子树上的第k-sum[i]小,即7-3=4,找到右子树上的第4小即可。直到找到某一个叶子节点,说明找到了我要找的第k小。这是通过权值线段树找到区间[1,n]上的第k小/大的应用。

那么知道了权值线段树是什么之后,主席树又是什么呢。主席树是一棵可持久化线段树,可持久化指的是它保存了这棵树的所有历史版本,最简单的办法是:如果你输入了n个数,那么每输入一个数字a[i],就构造一棵保存了从a[1]到a[i]的权值线段树。之所以这么做,是因为我们可以把第j棵树和第(i-1)棵树上的每个点的权值相减,来得到一颗新的权值线段树,而这个新的权值线段树相当于是输入了a[i]到a[j]以后得到的。如果这么说不太好理解的话,我们可以思考另外一个模型:求数组a[1]到a[n]的和。如果只是求[1,n]这一段的和,那么我们直接全部加起来就可以了,或者求一个前缀和sum[n]即可。那么如果我给定了l和r,想要知道[l,r]这段区间上的和呢?是不是利用前缀和sum[r]-sum[l-1]就可以轻松得到?那么主席树的思想也是如此,将tree[r]-tree[l-1]得到的一棵权值线段树即为属于[l,r]的一棵权值线段树,那么在这么一棵权值线段树上求第k大不是就转变为之前的问题了么。如果还是没有理解为什么可以用tree[r]-tree[l-1]来表示属于[l,r]的权值线段树,可以自己构造一个数组,然后画出属于[1,l-1],[1,r]和[l,r]的三颗权值线段树,来自己研究研究,多自己动手也不是一件坏事嘛。

还有一个问题需要解决,那就是空间问题。显而易见的是,如果每输入一个数就重新构造一棵权值线段树,必然会导致空间不够用:一棵线段树的空间就是n*4,那么一共的空间开销就是n*n*4,显然是会MLE的。那么这个问题怎么解决呢?可以发现每更新一个点,就会从它开始把它的所有祖先都更新一次,而其他的点都没有被改变,即:每次改变的结点只有logn个。这样,我们每次输入一个数,只需要多开logn个空间,那么实际的空间开销只有n*(4+logn),满足了空间要求。

以两道基础题结束。(代码主要仿照卿学姐的视频中的代码)

POJ-2104

AC代码:

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll ;
const int oo=0x7f7f7f7f ;
const int maxn=1e5+7;
const int mod=1e9+7;
int n,m,cnt,root[maxn],a[maxn],x,y,k;
struct node{
    int l,r,sum;
}T[maxn*25];
vector<int> v;
int getid(int x){
    return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
void update(int l,int r,int &x,int y,int pos){
    T[++cnt]=T[y],T[cnt].sum++,x=cnt;
    if(l==r) return;
    int mid=(l+r)/2;
    if(mid>=pos) update(l,mid,T[x].l,T[y].l,pos);
    else update(mid+1,r,T[x].r,T[y].r,pos);
}
int query(int l,int r,int x,int y,int k){
    if(l==r) return l;
    int mid=(l+r)/2;
    int sum=T[T[y].l].sum-T[T[x].l].sum;
    if(sum>=k) return query(l,mid,T[x].l,T[y].l,k);
    else return query(mid+1,r,T[x].r,T[y].r,k-sum);
}
int main(void){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),v.push_back(a[i]);
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());

    for(int i=1;i<=n;i++) update(1,n,root[i],root[i-1],getid(a[i]));
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&x,&y,&k);
        printf("%d\n",v[query(1,n,root[x-1],root[y],k)-1]);
    }

    return 0;
}

HDU-2665

AC代码:

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll ;
const int oo=0x7f7f7f7f ;
const int maxn=1e5+7;
const int mod=1e9+7;
int t,n,m,cnt,root[maxn],a[maxn],x,y,k;
struct node{
    int l,r,sum;
}T[maxn*25];
vector<int> v;
int getid(int x){
    return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
void update(int l,int r,int &x,int y,int pos){
    T[++cnt]=T[y],T[cnt].sum++,x=cnt;
    if(l==r) return;
    int mid=(l+r)/2;
    if(mid>=pos) update(l,mid,T[x].l,T[y].l,pos);
    else update(mid+1,r,T[x].r,T[y].r,pos);
}
int query(int l,int r,int x,int y,int k){
    if(l==r) return l;
    int mid=(l+r)/2;
    int sum=T[T[y].l].sum-T[T[x].l].sum;
    if(sum>=k) return query(l,mid,T[x].l,T[y].l,k);
    else return query(mid+1,r,T[x].r,T[y].r,k-sum);
}
int main(void){
    scanf("%d",&t);
    while(t--){
        v.clear();
        cnt=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]),v.push_back(a[i]);
        sort(v.begin(),v.end());
        v.erase(unique(v.begin(),v.end()),v.end());

        for(int i=1;i<=n;i++) update(1,n,root[i],root[i-1],getid(a[i]));
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&x,&y,&k);
            printf("%d\n",v[query(1,n,root[x-1],root[y],k)-1]);
        }
    }
	return 0 ;
}

之所以把hdu-2665也放上来,是因为在这道题的初始化上踩了坑,只记得把vector清空,忘记把作为存储初始值的cnt给赋为0,也算是一个提醒吧。顺带一提,hdu-2665的题意说的是求区间第k大,但是区间第k大wa了,而区间第k小AC了,很奇怪2333。

权值线段树 详解+操作模板(c++) 权值线段树详解+模板代码+例题 阅读详情

相关推荐

权值线段树/主席树学习笔记+例题

0. 介绍 以下转自:大佬 还有知乎有一篇比较好的介绍: 浅谈权值线段树到主席树 1.前言 据说主席树这个名字的由来呢,是因为创始人的名字缩写hjt与某位相同,然后他因为不会划分树于是自创了这一个数据结构。好强啊orz 主席树能实现什么操作呢?最经典的就是查询区间第k小了,其他的还有诸如树上路径第k小啦,带修改第k小啦之类的。以静态区间第k小为例 2.定义 先贴一下某神犇对主席树的理解:所谓主席树...

急流勇进 2436

数据结构 线段树--权值线段树 详解

一、权值线段树 简介 1.线段树 线段树是一种用于维护区间信息的高效数据结构,可以在 O(log⁡N)O(\log N)O(logN) 的时间复杂度内实现单点修改、区间修改、区间查询(区间求和,求区间最大值,求区间最小值)等操作。 线段树维护的信息必须满足可加性,即能以可以接受的速度合并信息和修改信息,包括在使用Lazy标记时,标记也要满足可加性 具体有关线段树的的讲解请参考博客:线段树 详解与模板

HeartFireY的博客 1万+

【算法学习】主席树入门

主席树入门 原理 主席树入门 主席树,也叫做可持久化线段树,准确来说,应该叫做可持久化权值线段树,因为其中的每一颗树都是一颗权值线段树。 所谓权值线段树,就是指线段树的叶子节点保存的是当前值的个数。这样说起来比较抽象,下面用具体例子来简单阐述。 如有数列:2 1 2 5 1 1 1 3,不难统计出,数列中数字1出现了4次,数字2出现了2次,数字3、数字5都出现了1次,对于这...

Pengwill's Blog 2万+

权值线段树

文章目录权值线段树定义原理区别用途操作例题(P1138 第 k 小整数)题目描述输入格式输出格式代码 权值线段树 定义 本质上仍然是一棵线段树,但它和每个节点用来表示一个区间内元素出现的次数,可以理解为维护区间的值域。 原理 现有序列:4 2 1 3 线段树初始状态各个节点权值是 0{0}0 依次插入元素4{4}4: 依次插入元素2{2}2: 依次插入元素1{1}1: 依次插入元素3{3}3: 区别 权值线段树维护的是桶,按值域开空间,维护的是个数。 简单线段树维护的是信息,按个数可开空间,维

Cauchy的博客 1907

主席树详解——区间的权值线段树

为啥叫主席树? 很多人一看到这名字觉得这肯定是个很厉害的数据结构,从而望而却步。 其实为啥这个数据结构叫主席树呢,emmmm… 这个数据结构是这位同学在考场上想出来的,而他的名字与某位主席缩写有一致的相似性QAQ 引入题(静态区间第k小) 题目描述 如题,给定 nnn 个整数构成的序列,将对于指定的闭区间查询其区间内的第 kkk 小值。 输入格式 第一行包含两个正整数 n,mn,mn,m,分别...

hipamp的博客 493

权值线段树和主席树入门

权值线段树和主席树入门PPT,权值线段树,顾名思义就是记录权值的线段树,普通的线段树直接以坐标为l,r建树,而权值线段树是以大小来建树,树上寸的信息是该权值的数量,而通过建树时二分从小到大的性质,可以用这个解决一些有序的东西

权值线段树和主席树的学习(待更新)

首先我们在学习主席树之前应该先学习权值线段树,因为最基本的主席树是在权值线段树的基础上建立起来的(当然不同的题目可能不太一样); 权值线段树之所以会带上“权值”二字,是因为它是记录权值的线段树。因此需要用到离散化操作来处理a[1-n]。记录权值指的是,每个点上存的是区间内的数字出现的总次数。比如一个长度为10的数组[1,1,2,3,3,4,4,4,4,5]。 这这颗权值线段树中,每一个节点维护的...

phacpf123 191

Verilator+VSCode实战:5分钟搞定Verilog语法检查与波形调试

本文详细介绍了如何将Verilator仿真器与VSCode编辑器高效集成,打造极速的Verilog开发工作流。通过环境配置、实时语法检查、一键仿真与波形生成等实战技巧,帮助IC设计工程师在几分钟内完成从代码编写到波形调试的全过程,大幅提升中小规模模块的验证效率。

weixin_28454475的博客 469

主席树【权值线段树】

​​​​​​一、权值线段树。 权值线段树,顾名思义,是建立在权值上的线段树。与普通的线段树不同【平时的线段树建立在定义域上,或者说位置下标上,比如说:一个1到n的序列,建立线段树后,根节点就存的是a[1]到a[n]的信息,根节点的左儿子就存的是a[1]到a[(1+n)/2]的信息,右儿子存的就是 a[(1+n)/2+1] 到a[n]的信息。】,权值线段树的叶子节点代表的是一个权值,而普通的线段树...

g21wcr的博客 1956

跨越移植陷阱:ESP-IDF下LVGL与ILI9341的组件化集成与常见避坑指南

本文详细解析了在ESP-IDF环境下将LVGL图形库与ILI9341显示屏驱动进行组件化集成的完整流程。重点介绍了移植过程中的关键配置策略、内存管理优化技巧以及常见问题解决方案,帮助开发者有效规避内存溢出、显示异常等典型陷阱,实现高效稳定的嵌入式GUI开发。

yhn456789的博客 623

C#的GDI+绘图详解

/消除锯齿 或 AntiAlias。// 1.在窗体或控件的Paint事件中,用PaintEventArgs e 创建绘图对象 ---- 控件或窗体重绘时。//为控件创建绘图对象。//--------------------以上方法三选一。//2.创建绘图对象 panel1中绘图。

weixin_50920631的博客 3457

权值线段树 基础入门知识详解

权值线段树 学习权值线段树,首先要了解线段树是什么。如果不会的可以先学习一下。 是什么 权值线段树,顾名思义是一棵线段树。 但它和普通线段树不同: 线段树,每个节点用来维护一段区间的最大值或总和等。 权值线段树,相当于一个桶,每个节点用来表示一个区间的数出现的次数。 为什么要用它 我们可以用它来维护一段区间的数出现的次数,从它的定义上来看,它可以快速计算一段区间的数的出现次数。 ...

ZSJZ_liuzian的博客 9204

从DDPM到DDIM:深入解读《Denoising Diffusion Implicit Models》

DDIM发表在ICRL2021上,是DDPM重要的改进之一,能显著提高DDPM的样本质量、减少采样时间,并且能显式控制插值,已经被广泛应用到现在的Diffusion Models上。这篇博客和大家一起详细解读一下DDIM,认识这一伟大的模型。.........

沉迷单车的追风少年 1万+

权值线段树及主席树的详解

这篇的重点是为各位简绍主席树的知识,当然在减少主席树之前,还需要一些准备知识 第一:离散化 离散化: 把无限空间有限个体映射到有限空间里有限 白话:在不改变数据相对大小的条件下,对数据进行相应的缩小 例如: 原数据:7 1 4 3处理后:4 1 3 2 原数据:{100,250}{200,400}处理后{1,3}{2,4} 离散化需要函数:unique函数(去重函数) low_bound(x,y,val)函数: 在(x,y)范围内返回>=val的第一个元素位置。如果所有元素都小于val,则返回last

malloch的博客 1474

清华源pip install出现ERROR: Could not find a version that satisfies the requirement的解决方案

本文主要介绍了清华源pip install出现ERROR: Could not find a version that satisfies the requirement的解决方案,希望能对学习python的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 8万+

AUTOSAR进阶图解==>AUTOSAR_SWS_DefaultErrorTracer

AUTOSAR Default Error Tracer (DET)是AUTOSAR架构中的核心错误追踪模块,提供统一的错误报告机制。DET能够处理开发错误、运行时错误和瞬态故障三类问题,支持模块级和实例级的配置管理。模块架构上,DET通过Det_API接口与其他模块交互,可配置转发错误至诊断事件管理器(DEM)或调试日志追踪(DLT)。其配置结构包含全局参数和模块实例参数,允许灵活控制错误报告行为。DET在AUTOSAR 4.3.0版本中从DevelopmentErrorTracer扩展而来,增强了错误处

一名留德华的,康德的信徒的,专注于汽车电子领域的博客 909

权值线段树和可持久化线段树(主席树)

权值线段树和可持久化线段树(主席树)

咸鱼势力登场 1112

Altera FPGA与高速ADS4249和DAC3482的LVDS接口设计

引言:本文以TI的ADS4249(ADC)和DAC3482(DAC)之间的接口为例,介绍Altera FPGA与ADC/DAC之间的DDR LVDS接口设计以及时序约束详细设计。本文介绍的实例可方便扩展到具有类似接口格式的其他高速数据转换器设计。

FPGA_Designer 1899

权值线段树(知识学习+板子总结)

概念 和线段树一样的函数, p这个区间里维护的是这段区间里的数出现的次数 每出现一个数x,叶子结点[x,x]这个区间就+1,删除就-1 支持动态查询第k大的数、数x出现的最小rank、 寻找x的前驱(即小于x的最大的数) 和寻找x的后继(即大于x的最小的数)等操作 思路来源 https://www.bilibili.com/video/av16552942?from=search&...

小衣同学的博客 1506

OSG三维渲染引擎编程学习之一:“第一章:OSG介绍” 之 “1.1 OSG简介”

第一章:OSG介绍; 1.1 OSG简介。

LuckyHanMo的博客 3223

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

权值线段树与主席树(初步)

1.首先,给你一颗值为横坐标的线段树,每个节点上存着该值出现了多少次,这样的一颗线段树你会求区间k大值吧.二分即可. 2.然后,假设区间是数组arr[n],区间长度是n,那么给你n颗线段树,第i颗线段树是第i-1颗线段树插入arr[i]得到. 3.如果你有了这n颗线段树,想求区间[l,r]中的第k大值,那么你需要在第r颗和第l-1颗线段树的差线段树上作二分,可以求得区间第k大值. 4.差线段...

mlm5678的博客 422

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

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

2019.11.4 今天总算弄会主席树了,发现确实不难,但是需要跳出常规线段树的思维,特别是处理子树上面 主席树的定义与作用 主席树,也称可持久化线段树,那么什么是可持久化线段树呢,即为一颗记录了所有更新过程的线段树。能够处理出从第i次更新到第j次更新的线段树变化,具体作用一会见例题。 主席树的功能 记录所有过程的线段树,按正常思维是需要开O(N*M)这么大的空间的,时间也为O(n*m),...

孙煜晗的博客 7009

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

权值线段树/主席树

权值线段树: 解释:就是一种可以维护数字权值的线段树 应用:逆序数,维护数字的出现次数,(主席树的基础) 例题:逆序队 #include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; typedef pair<ll, int> pli;...

weixin_43870114的博客 218

树状数组套权值线段树 学习笔记

树状数组套权值线段树 首先要知道权值线段可以处理全局第 K 大;主席树可以处理静态区间第 K 大,所谓静态就是不能改变值;但是如果有修改操作,用主席树做,每次要修改,后面的所有主席树都要进行一次修改,复杂度为 O(n); 显然是不行的; 这里就可以用到树状数组维护前缀和,权值线段树维护区间信息; 换句话说就是树状数组每个结点换成权值线段树,主体思想还是跟主席树一样,利用前缀和求某个区间第 K 大(...

不知所云的博客 627

权值线段树理解及模板

权值线段树,顾名思义就是记录权值的线段树,普通的线段树直接以坐标为l,r建树,而权值线段树是以大小来建树,树上寸的信息是该权值的数量,而通过建树时二分从小到大的性质,可以用这个解决一些有序的东西 这个视频讲得很好,还有主席树的东西 https://www.bilibili.com/video/av16552942/?p=1&share_source=qq&share_medium=...

- 回忆゛ 1034
上一篇: hdu 4496 - D-City (基础并查集)
下一篇: Codeforces 981D Bookshelves(贪心+dp)
Stupid_Turtle
博客等级 码龄9年 25粉丝 18原创
评论 12
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值