1549:最大数——线段树

news2024/11/19 9:38:17

【题目描述】
原题来自:JSOI 2008

给定一个正整数数列 a1,a2,a3,⋯,an ,每一个数都在 0∼p–1 之间。可以对这列数进行两种操作:

添加操作:向序列后添加一个数,序列长度变成 n+1;

询问操作:询问这个序列中最后 L 个数中最大的数是多少。

程序运行的最开始,整数序列为空。写一个程序,读入操作的序列,并输出询问操作的答案。

【输入】
第一行有两个正整数 m,p,意义如题目描述;

接下来 m 行,每一行表示一个操作。如果该行的内容是 Q L,则表示这个操作是询问序列中最后 L 个数的最大数是多少;如果是 A t,则表示向序列后面加一个数,加入的数是 (t+a)modp。其中,t 是输入的参数,a 是在这个添加操作之前最后一个询问操作的答案(如果之前没有询问操作,则 a=0)。

第一个操作一定是添加操作。对于询问操作,L>0 且不超过当前序列的长度。

【输出】
对于每一个询问操作,输出一行。该行只有一个数,即序列中最后 L 个数的最大数。

【输入样例】
10 100
A 97
Q 1
Q 1
A 17
Q 2
A 63
Q 1
Q 1
Q 3
A 99
【输出样例】
97
97
97
60
60
97
【提示】
样例说明

最后的序列是 97,14,60,96。

数据范围与提示:

对于全部数据,1≤m≤2×105,1≤p≤2×109,0≤t<p。

分析

  1. 有关线段树的详细知识,可以参考:线段树蓝书讲解 + 经典例题AcWing 1275. 最大数,讲的非常好,还介绍了,如果题目给了用于建立线段树的初始数组a,应该如何初始化(给data赋值);
  2. 此题属于单点修改、区间查询,单点修改不涉及懒标记,然后这里介绍下四个函数:pushup、bulid、query、modify;
  • pushup(u):由儿子节点信息,计算父亲结点信息,参数u就是当前父亲结点的编号,此题data存区间最大值,所以直接取其左右孩子的区间最大值即可;
  • build(u,l,r):就是建立线段树,u为当前的结点编号,l,r为当前准备分配的区间,先把当前的[l,r]全赋值给父亲u管理,然后我们再把 [l,r]劈开(l+r>>1),一半让u的左孩子管理,另一半让u的右孩子管理;递归建树,当区间只有一个值(l==r),说明分配完毕,那就return;
  • query(u,l,r):查询[l,r]的区间最大值,然后当前想要查询的区间[l,r]和结点u存在三种关系:1. 所查询区间[l,r] 完全覆盖(包含)了 u结点所代表的区间,直接返回当前u的data(因为没必要再去看看哪个孩子管理的[l,r]);2.所查询区间 [l,r] 和 u的左孩子有交集(l<=mid),那就递归左子树;3. [l,r] 和 u的右孩子有交集(r>=mid+1),那就递归右子树 (当然[l,r]可能和左右孩子都有交集,所以这里就不是else了)
  • modify(u,x,v):x为所要修改的结点编号,v为想要修改的值;那就先从根节点开始找到叶子结点所在位置,找的时候,判断x在u的左孩子,还是右孩子,然后递归找,如果找到(l <= t[u].l && r >= t[u].r)更新他的值,递归完u的左右子树后,通过pushup更新下当前结点u的data;
  1. 要分清mid= l + r >> 1 和 mid = t[u].l + t[u].r >> 1,前者是建树的时候,区间拆为两半,来让左右孩子管理;后者为在确定某个结点或某段区间(区间和mid的比较当然是用区间的端点进行比较),是在当前结点u的左子树、还是右子树;

下图为yxc画的线段树的大概结构,以及一些位运算表示的含义;
在这里插入图片描述
在这里插入图片描述

#include <bits/stdc++.h>

using namespace std;

const int N = 200010;
struct node {
    int l, r;
    int data; //当前区间[l,r]的最大值
};
int m, p;
node t[4 * N];

//由儿子节点信息,计算父亲结点信息
void pushup(int u) {
    //u为当前父亲结点的编号,此题data存最大值
    t[u].data = max(t[u << 1].data, t[u << 1 | 1].data);
}

void build(int u, int l, int r) {
    //结点编号为u的所代表的区间[l,r]
    t[u].l = l, t[u].r = r;
    //叶子结点
    if (l == r)
        return;
    int mid = l + r >> 1;
    //递归左右子树:左孩子结点编号2*u,区间[l,mid] ;左孩子结点编号2*u+1,区间[mid+1,r]
    build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}

//1. [l,r] 完全覆盖了 u结点所代表的区间,直接返回当前u的data
//2. [l,r] 和 u的左孩子有交集(l<=mid),那就递归左子树
//3. [l,r] 和 u的右孩子有交集(r>=mid+1),那就递归右子树  (当然可能和左右孩子都有交集,所以这里就不是else了)
int query(int u, int l, int r) {
    //1.[l,r]包住了结点u的区间
    if (l <= t[u].l && r >= t[u].r)
        return t[u].data;
    int mid = t[u].l + t[u].r >> 1;
    int res = 0;
    //2.所查找区间[l,r]和u的左孩子2*u有交集
    if (l <= mid)
        res = max(res, query(u << 1, l, r));
    //3.所查找区间[l,r]和u的右孩子2*u+1有交集,这里是if,不是else
    if (r >= mid + 1)
        res = max(res, query(u << 1 | 1, l, r));
    return res;
}

//先找到叶子结点,从下往上更新; x为所要修改的结点编号,v为想要修改的值
void modify(int u, int x, int v) {
    //找到叶子结点
    if (t[u].l == x && t[u].r == x) {
        t[u].data = v;
        return;
    }
    int mid = t[u].l + t[u].r >> 1;
    //向u的左孩子方向找叶子结点x
    if (x <= mid)
        modify(u << 1, x, v);
    else //x在u的右孩子
        modify(u << 1 | 1, x, v);
    //从下往上回溯更新父亲结点信息
    pushup(u);
}

int main() {
    cin >> m >> p;
    int cnt = 0;//当前有效结点(数据)的个数
    int last = 0;//上一次查询时候得到的结果
    //建树,根的总区间 [1,m]
    build(1, 1, m);

    char op[2];
    int x;
    while (m--) {
        scanf("%s%d", &op, &x);
        if (op[0] == 'Q') {
            //查询后x个数
            last = query(1, cnt - x + 1, cnt);
            printf("%d\n", last);
        } else {
            //把cnt+1的位置的数修改(添加)
            modify(1, cnt + 1, (last + x) % p);
            cnt++;
        }
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/112547.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据库系统概论笔记

数据库系统概论(王珊 萨师煊 编著)笔记。 第一章 绪论 1.数据库系统概述 1.1数据库的4个基本概念 数据&#xff1a;描述事物的符号记录称为数据。数据的含义称为数据的语义&#xff0c;数据与其语义是不可分的。数据库&#xff1a;长期存储在计算机内、有组织的、可共享的大…

fpga实操训练(仿真和状态机)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 在进行fpga上板子实验之前&#xff0c;相信很多同学都是通过仿真的方式来实现verilog学习的。仿真比较容易&#xff0c;也不需要依赖物理硬件&…

offsetTop、clientTop、scrollTop等属性详解【概念+详细例子分析】

文章目录一、 offsetscrollclient详细讲解1-1 offset系列1-2 client系列1-3 scroll系列二、 一张图片即可理解一、 offsetscrollclient详细讲解 1-1 offset系列 MDN中offset… offsetWidth/offsetHeight :对象的可见宽度offsetLeft/offsetTop&#xff1a; 当前元素距浏览器边界…

AcWing第 82 场周赛

第k个数 给定一个长度为 nn 的整数数列 a1,a2,…,ana1,a2,…,an&#xff0c;以及一个整数 kk。 请你计算并输出该数列从大到小排序后的第 kk 个数。 输入格式 第一行包含两个整数 n,kn,k。 第二行包含 nn 个整数 a1,a2,…,ana1,a2,…,an。 输出格式 一个整数&#xff0c…

map与set详解

&#x1f9f8;&#x1f9f8;&#x1f9f8;各位大佬大家好&#xff0c;我是猪皮兄弟&#x1f9f8;&#x1f9f8;&#x1f9f8; 文章目录一、两个概念二、set①set的两种遍历方式②set的erase③set的count三、map①SGI-STL中关于键值对的定义②map的insert③访问键值对④map的op…

docker redis容器化(极简教程)

1.通过redis-cli连接你原来的redis&#xff0c;进入后输入info&#xff0c;查看到具体版本号 2.下载redis官方镜像,docker pull redis:你的版本号 3.创建一个新文件夹redis&#xff0c;mkdir -r /hadoop/redis 4.复制你原来的redis.conf&#xff0c;到redis文件夹中,cp /usr/l…

c语言 指针进阶5 6 自定义冒泡函数 qsort

指向函数指针数组的指针 回调函数 如何使用 一个函数可以实现加减乘除 calc&#xff08;&#xff09; 不同点通过函数参数传进去 代码解释如下 int Add(int x, int y) {return x y; } int Sub(int x, int y) {return x - y; } int Mul(int x, int y) {return x * y; } in…

JDBC -- API

目录 DriverManager 驱动管理类 作用 注册驱动 获取数据库连接 Connection 数据库连接对象 作用 获取执行SQL的对象 管理事务 Statement 作用 执行SQL语句 ResultSet 结果集对象 作用 封装了DQL查询语句的结果 获取查询结果 PreparedStatement 作用 预编译SQ…

C#大型医院HIS系统源码 医院信息管理系统源码 C/S架构 VS2013+sql2012

了解更多源码内容&#xff0c;可私信我。 开发环境&#xff1a;VS2013sql2012 C/S架构 一、门诊系统&#xff1a; 1、挂号与预约系统:实现了医院门诊部挂号处所需的各种功能&#xff0c;包括门诊安排的管理&#xff0c;号表的生成及维护&#xff0c;门诊预约管理和挂号处理&…

6. SSM整合

1. SSM整合配置 SM整合流程 创建工程SSM整合 Spring SpringConfig MyBatis MybatisConfigJdbcConfigjdbc.properties SpringMVC ServletContainerInitConfigSpringMvcConfig 1.1 创建工程&#xff0c;添加依赖和插件 <dependencies><dependency><groupId&g…

【LeetCode】解数独 [H](深度优先遍历)

37. 解数独 - 力扣&#xff08;LeetCode&#xff09; 一、题目 编写一个程序&#xff0c;通过填充空格来解决数独问题。 数独的解法需 遵循如下规则&#xff1a; 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的 3x3 宫内只…

设计模式-责任链模式

一、知其然 责任链字面含义第一联想到的就是他是一个链式的行为&#xff0c;就像一个链条一样把所产生的动力传输到到齿轮上一样&#xff1b;还有类似生活中的一个游戏“击鼓传花”&#xff0c;这样说好像也是泛泛而谈&#xff0c;来看看度娘的官方概念&#xff08;摘自百度百科…

[每周一更]-(第26期):反爬虫机制

随着网站的越来越普及&#xff0c;我们开发出来的知识类网站更不希望被竞争对手爬虫&#xff0c;虽然现在网络中充斥着各种各样的蜘蛛&#xff0c;有合法的浏览器爬虫&#xff0c;以及不合法 的人为爬虫&#xff0c;所以攻防战一直都存在&#xff0c;我们只能更好的设定规则&am…

中文文本分类

手把手带你做一个文本分类实战项目(模型代码解读) https://www.bilibili.com/video/BV15Z4y1S7aR/?spm_id_from333.788.recommend_more_video.-1&vd_sourcec47fbb8166930edc486d8fdc405bf569 中文汉字对应的数字索引 之后对应的数字索引 之后找到tokn embedding的东西 1…

34. 池化层 / 汇聚层

1. 池化层 如果我们拍摄黑白之间轮廓清晰的图像X&#xff0c;并将整个图像向右移动一个像素&#xff0c;即Z[i, j] X[i, j 1]&#xff0c;则新图像Z的输出可能大不相同。而在现实中&#xff0c;随着拍摄角度的移动&#xff0c;任何物体几乎不可能发生在同一像素上。即使用三脚…

15【SpringMVC的注解开发】

文章目录二、SpringMVC注解支持2.1 回顾Servlet容器启动源码流程2.2 分析SpringMVC启动源码分析2.2.1 SpringServletContainerInitializer源码分析2.2.2 WebApplicationInitializer源码分析1&#xff09;AbstractContextLoaderInitializer2&#xff09;AbstractDispatcherServl…

短视频播放量超10w后,流量变少的问题解决方案

短视频播放量超10w后&#xff0c;流量变少的问题解决方案 上一篇我们聊了视频播放超10w后&#xff0c;会遇到流量变少的问题并分析了可能的原因&#xff0c;既然知道了原因&#xff0c;那么我们就可以针对性的去解决了。 今天给大家聊一聊在我赢助手跟超200名短视频创作者沟通…

Allegro如何设置差分动态等长规则操作指导

Allegro如何设置差分动态等长规则操作指导 Allegro上可以对差分设置动态等长规则,让差分对在任意一段距离上都是满足等长误差的,尤其是在差分对走线较长的情况下 以下面这两对线为例 具体操作如下 打开constraint Manage选择Physical规则

Linux 管理联网 设置主机名( nmtui图形化 和 hostnamectl命令 )

设置主机名 # 常用的有两种方式&#xff0c;一种是 nmtui 图形化界面的方式来设置&#xff0c; 一种是 hostnamectl 命令的方式来设置。 nmtui 直接在命令行 输入 nmtui 便进入 图形化界面 >>> 最后一选项&#xff08; 红底&#xff09; 便是 设置主机名~&#x…

微导纳米科创板上市:市值125亿 无锡首富王燕清再敲钟

雷递网 雷建平 12月23日江苏微导纳米科技股份有限公司&#xff08;简称&#xff1a;“微导纳米”&#xff0c;股票代码为&#xff1a;“688147”&#xff09;今日在科创板上市。微导纳米此次发行4544.55万股&#xff0c;发行价为24.21元&#xff0c;募资总额为11亿元。微导纳米…