权值线段树、主席树学习

权值线段树总结 权值线段总结 权值线段树就是把线段树的每个点权,赋予一定的含义,比如数字出现的次数,数值前缀出现的次数,并用区间求和维护一个前缀信息,比如数字出现的次数,第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

uds协议之can总线程序升级

uds协议简介 如何利用uds协议升级 升级流程 uds服务类型介绍

fangye945a的博客 1万+

主席树【权值线段树】

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

g21wcr的博客 1956

深信服技术认证“SCCA-C”划重点:信服云托管云

该认证包括云数据中心基础、云计算基础、云计算关键技术、云计算交付和运维体系、云计算技术商业应用、信服云托管云、深信服超融合HCI、深信服桌面云aDesk、深信服分布式存储EDS、深信服应用交付AD。学习并获得SCCA-C认证后,可以具备深信服产品功能原理与实践,能够根据业务需求,协助完成云产品方案落地与实施;能够根据业务需求,完成深信服云产品的部署和管理的基本工作。为帮助大家更加系统化地学习云计算知识,高效通过云计算工程师认证,深信服特推出“SCCA-C认证备考秘笈”,共十期内容。

sangfor_edu的博客 613

Unipush2.0 App消息推送(在线+离线推送)

使用unipush2.0进行消息推送,包含在线跟离线

weixin_50251467的博客 3699

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

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

ZSJZ_liuzian的博客 9204

PMSM无感foc控制(滑模-反正切-PLL)【仿真模型搭建教程】(附模型)

本文主要目的是教大家如何把文献中的公式转换成仿真模型。 首先介绍滑模控制的原理及如何搭建simulink模型。 1.1基于反电势估计位置原理 永磁同步电机在静止坐标系αβ下的电压方程: 扩展反电动势包含转子位置信息,并且αβ轴下扩展反电动势的反正切函数正好就等于位置角theta。 1.2 滑模控制原理(比较重要的点是以电机电流模型推导展开) 通过滑模观测得到鲁棒性比较高的αβ轴下扩展反电动势,并求其反正切函数,得到位置信息。 /*********************...

weixin_44769876的博客 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

YOLO项目部署:从Python脚本到Docker容器的企业级交付全流程

YOLO模型企业级Docker部署方案 核心挑战 环境一致性:解决"本地能跑,服务器崩掉"问题 可扩展性:支持单实例到多实例扩展 稳定性:确保99.9%可用性 部署流程 项目改造:模块化代码,分离配置 Docker镜像:支持CPU/GPU环境 API服务:封装推理逻辑 监控告警:实现自动化运维 技术方案 需求 解决方案 环境一致性 Docker镜像+依赖冻结 可扩展性 K8s+负载均衡 稳定性 健康检查+自动重启 项目结构 模块化代码组织 外部化配置管理 精确依赖版本控制 摘要重点:通过

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1230

k8s infiniband 和 RoCE(RDMA over Converged Ethernet)

vendors 为设备厂商编号,注意这里不是 ibv_devinfo 命令看到的vendor_id 的值,而是 lspci -n |grep “网卡的bdf” 得到的。如上文所述,启动了两个测试 pod ,登录其中一个 pod(该 pod roce 设备 ip 为 10.56.217.79)如上文所述,启动了两个测试 pod ,登录其中一个 pod(该 pod ip 为 10.96.225.24)说明:文中用到的镜像是自定义的,文末有其Dockerfile 文件。修改该文件,增加污点容忍的内容,如下。

weixin_40548182的博客 1795

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

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

咸鱼势力登场 1112

Python爬虫实战:如何爬取12306列车信息

本文介绍了如何使用Python编写爬虫,抓取12306列车信息。我们讲解了如何分析12306的列车数据接口,如何发送HTTP请求,解析返回的JSON数据,并将数据保存到本地文件中。我们还讨论了如何绕过反爬虫机制,如使用随机User-Agent和设置请求延时。通过这个实战项目,你应该掌握了如何爬取并解析来自公共API的数据,同时提高了你的爬虫技能。这些技能不仅适用于12306列车信息抓取,也可以广泛应用于其他需要抓取JSON数据的网站。

2201_76125261的博客 1922

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

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

小衣同学的博客 1506

Allegro如何改变线宽操作指导

用Allegro做pcb设计的时候,改变走线线宽是非常常用的功能,如下图。线宽目前是12mil,需要把线宽改成15mil。如何改变线宽操作指导。

weixin_54787054的博客 4254

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

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

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

mlm5678的博客 422

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

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

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

孙煜晗的博客 7009

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

权值线段树/主席树

权值线段树: 解释:就是一种可以维护数字权值的线段树 应用:逆序数,维护数字的出现次数,(主席树的基础) 例题:逆序队 #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、付费专栏及课程。

余额充值