当前位置: 首页 > news >正文

可持久化线段树

 可持久化线段树相比可持久化Trie来说要简单一点,因为线段树的结构固定,无论如何添加信息结构都不会改变,时间复杂度为O(nlogn)

可持久化线段树维护的是值域,在数值上建立线段树,并维护每个数值区间一共有多少数

例题:第k小数255. 第K小数 - AcWing题库 

给定长度为 N 的整数序列 A,下标为 1∼N。

现在要执行 M 次操作,其中第 i 次操作为给出三个整数 li , ri , ki,求 A[ li ],A[ li+1 ],…,A[ ri ] (即 A 的下标区间 [ li,ri ])中第 ki 小的数是多少。

输入格式

第一行包含两个整数 N 和 M。

第二行包含 N 个整数,表示整数序列 A。

接下来 M 行,每行包含三个整数 li ,ri ,ki ,用以描述第 i 次操作。

输出格式

对于每次操作输出一个结果,表示在该次操作中,第 k 小的数的数值。

每个结果占一行。

数据范围

N ≤ 105,M ≤ 104,|A[i]| ≤ 109

输入样例:

7 3
1 5 2 6 3 7 4
2 5 3
4 4 1
1 7 3

输出样例: 

5
6
3

 解题思路:

先来想如何求整体的第k小数,只需要递归即可,现在加入了区间限制,如果求的是1~R的第k小数,则只需要找刚好加完R个数的线段树版本,如果求的是1~L的第k小数,则只需要找刚好加完L个数的线段树版本,如果求的是L~R的第k小数,则可以用前缀和思想,用R的版本减去L的版本

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

const int N=100010,M=10010;

int n,m;
int a[N];
vector<int> nums;

struct node
{
    int l,r;
    int cnt;
}tr[N * 4 + N * 17];

int root[N],idx;

int find(int x)
{
    return lower_bound(nums.begin(),nums.end(),x) - nums.begin();
}

int build(int l,int r)
{
    int p = ++ idx;
    if(l == r)
    return p;
    int mid= l + r >> 1;
    tr[p].l=build(l,mid),tr[p].r=build(mid + 1,r);
    return p;
}

int insert(int p,int l,int r,int x)
{
    int q= ++ idx;
    tr[q]=tr[p];
    if(l == r)
    {
        tr[q].cnt++;
        return q;
    }
    int mid = l + r >> 1;
    if(x <= mid)
    tr[q].l = insert(tr[p].l,l,mid,x);
    else
    tr[q].r = insert(tr[p].r,mid + 1,r,x);
    tr[q].cnt = tr[tr[q].l].cnt + tr[tr[q].r].cnt;
    return q;
}

int query(int q,int p,int l,int r,int k)
{
    if(l == r)
    return r;
    int cnt=tr[tr[q].l].cnt - tr[tr[p].l].cnt;
    int mid = l + r >> 1;
    if(k<=cnt)
    return query(tr[q].l,tr[p].l,l,mid,k);
    else
    return query(tr[q].r,tr[p].r,mid + 1,r,k - cnt);
}

int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i ++)
    {
        scanf("%d", &a[i]);
        nums.push_back(a[i]);
    }
    
    sort(nums.begin(),nums.end());
    nums.erase(unique(nums.begin(),nums.end()),nums.end());
    
    root[0]=build(0,nums.size()-1);
    
    for(int i = 1; i <= n; i ++)
    {
        root[i] = insert(root[i - 1],0,nums.size() - 1,find(a[i]));
    }
    
    while(m--)
    {
        int l,r,k;
        scanf("%d%d%d",&l,&r,&k);
        printf("%d\n",nums[query(root[r],root[l - 1],0,nums.size() - 1,k)]);
    }
}

相关文章:

  • 计算机网络-网络层篇-子网划分
  • DataX 初识
  • 工程项目管理——第十章 软件项目团队计划
  • 基于Java+SpringBoot+Thymeleaf+Mysql摄影图片分享网站系统设计与实现
  • C#的Dictionary类使用说明
  • 【FPGA教程案例90】机器视觉1——通过FPGA实现基于颜色模型的交通灯检测,使用MATLAB辅助测试
  • winform中c#调用第三方、opencv原生dll库图像处理
  • DS1302 / DS1307 不起振可能是寄存器配置原因
  • 大数据讲课笔记1.7 软件包管理器RPM与yum
  • Python数据类型:序列(列表list、元组tuple、字符串str)
  • 解决VueCropper导致的后端接收文件后缀名为blob的问题
  • [Codeforces] number theory (R1600) Part.11
  • 基于JAVA火车订票系统计算机毕业设计源码+数据库+lw文档+系统+部署
  • 【CSDN:国庆活动】——blink动态里的学习成长
  • SpringBoot+Vue项目计算机等级考试报名系统
  • 【从零开始安装kubernetes-1.7.3】2.flannel、docker以及Harbor的配置以及作用
  • Android 初级面试者拾遗(前台界面篇)之 Activity 和 Fragment
  • Android路由框架AnnoRouter:使用Java接口来定义路由跳转
  • Angular js 常用指令ng-if、ng-class、ng-option、ng-value、ng-click是如何使用的?
  • C学习-枚举(九)
  • docker容器内的网络抓包
  • E-HPC支持多队列管理和自动伸缩
  • ES6, React, Redux, Webpack写的一个爬 GitHub 的网页
  • go语言学习初探(一)
  • IndexedDB
  • Lucene解析 - 基本概念
  • MobX
  • vue中实现单选
  • 对象管理器(defineProperty)学习笔记
  • 前端学习笔记之观察者模式
  • 容器服务kubernetes弹性伸缩高级用法
  • 提醒我喝水chrome插件开发指南
  • 微信开源mars源码分析1—上层samples分析
  • 译自由幺半群
  • 用 vue 组件自定义 v-model, 实现一个 Tab 组件。
  • Java总结 - String - 这篇请使劲喷我
  • # 数论-逆元
  • #《AI中文版》V3 第 1 章 概述
  • #14vue3生成表单并跳转到外部地址的方式
  • #微信小程序(布局、渲染层基础知识)
  • #我与Java虚拟机的故事#连载01:人在JVM,身不由己
  • #我与Java虚拟机的故事#连载17:我的Java技术水平有了一个本质的提升
  • (C#)Windows Shell 外壳编程系列9 - QueryInfo 扩展提示
  • (js)循环条件满足时终止循环
  • (zhuan) 一些RL的文献(及笔记)
  • (附源码)springboot 房产中介系统 毕业设计 312341
  • (六)vue-router+UI组件库
  • (十八)devops持续集成开发——使用docker安装部署jenkins流水线服务
  • **PHP分步表单提交思路(分页表单提交)
  • .bat批处理(五):遍历指定目录下资源文件并更新
  • .MSSQLSERVER 导入导出 命令集--堪称经典,值得借鉴!
  • .NET 中使用 TaskCompletionSource 作为线程同步互斥或异步操作的事件
  • .net打印*三角形
  • .NET开源项目介绍及资源推荐:数据持久层
  • ??javascript里的变量问题