题目描述

老管家是一个聪明能干的人。他为财主工作了整整10年,财主为了让自已账目更加清楚。要求管家每天记k次账,由于管家聪明能干,因而管家总是让财主十分满意。但是由于一些人的挑拨,财主还是对管家产生了怀疑。于是他决定用一种特别的方法来判断管家的忠诚,他把每次的账目按1,2,3…编号,然后不定时的问管家问题,问题是这样的:在a到b号账中最少的一笔是多少?为了让管家没时间作假他总是一次问多个问题。

分析

关于线段树的详细讲解可以参考拙作(点击传送门):【算法微解读】浅谈线段树

那么我们就开始讲解一下这一道模板题,题目的主要意思就是区间查询最小值。

首先定义线段树的节点的状态segment_tree_node

struct segment_tree_node{//线段树节点状态
int Min;//表示当前区间的最小值
}tree[maxn];

接下来就是建树build的过程了。

void build(int l,int r,int nod) {//建树
if (l==r) {//如果l与r指针相撞,那么就是已经到了目标区间,赋值
tree[nod].Min=a[l];
return;
}
int mid=(l+r)>>1;//取中间mid
build(l,mid,lson); build(mid+1,r,rson);//lson和rson可以恒定义一下,缩短代码
pushup(nod);//更新父节点
}

建树好之后,我们要进行一下区间查询的操作,区间查询的本质其实就是将原区间分成两部分,然后对每一个区间的目标区间进行查询。

|----l----|----r----|当做是原区间

  • 情况一:[ll,rr]区间在l区间内,那么就是query(l,mid,ll,rr,lson)意思就是在[l,mid]区间内查询[ll,rr]
  • 情况二:[ll,rr]区间在r区间内,那么就是query(mid+1,r,ll,rr,lson)意思就是在[mid+1,r]区间内查询[ll,rr]
  • 情况三:[ll,rr]区间一部分在l区间内,一部分在r区间内,那么就要把原区间和目标区间都分成两部分,因为线段树中同一深度的区间互不干扰,那么我们就查询query(l,mid,ll,mid,lson),query(mid+1,r,mid+1,rr,rson)

注:区间查询一般是不需要pushup的,但是如果之前是有区间修改,那么是要pushdown的。

那么我们通过代码来详细的看一下区间查询最小值是如何写的。

int query(int l,int r,int ll,int rr,int nod) {//区间查询最小值
if (l==ll&&r==rr) return tree[nod].Min;//已经找到了目标区间
int mid=(l+r)>>1;//取中间
if (rr<=mid) return query(l,mid,ll,rr,lson);//整个区间在mid的左边
else if (ll>mid) return query(mid+1,r,ll,rr,rson);//整个区间在mid的右边
else return min(query(l,mid,ll,mid,lson),query(mid+1,r,mid+1,rr,rson));//区间被mid分成两部分
}

主程序就不写了,也是很简单的

恒定义:define lson nod<<1 define rson (nod<<1)+1

完整代码

#include <bits/stdc++.h>
#define lson nod<<1
#define rson (nod<<1)+1
#define ms(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=100000<<2;
const int inf=1<<30;
struct segment_tree_node{//线段树节点状态
int Min;
}tree[maxn];
int n,m;
int a[maxn>>2];
inline int read() {
int x=0,w=0; char ch=0;
while (!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return w?-x:x;
}
void pushup(int nod) {//pushup操作,更新父节点内的信息
tree[nod].Min=min(tree[lson].Min,tree[rson].Min);
}
void build(int l,int r,int nod) {//建树
if (l==r) {//如果l与r指针相撞,那么就是已经到了目标区间,赋值
tree[nod].Min=a[l];
return;
}
int mid=(l+r)>>1;//取中间mid
build(l,mid,lson); build(mid+1,r,rson);//lson和rson可以恒定义一下,缩短代码
pushup(nod);//更新父节点
}
int query(int l,int r,int ll,int rr,int nod) {//区间查询最小值
if (l==ll&&r==rr) return tree[nod].Min;//已经找到了目标区间
int mid=(l+r)>>1;//取中间
if (rr<=mid) return query(l,mid,ll,rr,lson);//整个区间在mid的左边
else if (ll>mid) return query(mid+1,r,ll,rr,rson);//整个区间在mid的右边
else return min(query(l,mid,ll,mid,lson),query(mid+1,r,mid+1,rr,rson));//区间被mid分成两部分
}
int main() {
ms(tree,inf);//先将树的每一个节点都赋值成inf,因为我们要求最小值
n=read(),m=read();
for (int i=1;i<=n;i++) a[i]=read();
build(1,n,1);
while (m--) {
int x=read(),y=read();
printf("%d ",query(1,n,x,y,1));
}
return 0;
}

【洛谷P1816 忠诚】线段树的更多相关文章

  1. 洛谷P1816 忠诚 题解

    洛谷P1816 忠诚 题解 题目描述 老管家是一个聪明能干的人.他为财主工作了整整10年,财主为了让自已账目更加清楚.要求管家每天记k次账,由于管家聪明能干,因而管家总是让财主十分满意.但是由于一些人 ...

  2. 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)

    To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...

  3. 洛谷P1816 忠诚

    P1816 忠诚 569通过 1.5K提交 题目提供者该用户不存在 标签云端 难度普及+/提高 时空限制1s / 128MB 提交  讨论  题解 最新讨论更多讨论 主席树的常数貌似大于线段树… TL ...

  4. 【模板】ST表 洛谷P1816 忠诚

    P1816 忠诚 题目描述 老管家是一个聪明能干的人.他为财主工作了整整10年,财主为了让自已账目更加清楚.要求管家每天记k次账,由于 管家聪明能干,因而管家总是让财主十分满意.但是由于一些人的挑拨, ...

  5. 洛谷 P1816 忠诚题解

    题目描述 老管家是一个聪明能干的人.他为财主工作了整整10年,财主为了让自已账目更加清楚.要求管家每天记k次账,由于管家聪明能干,因而管家总是让财主十分满意.但是由于一些人的挑拨,财主还是对管家产生了 ...

  6. 【洛谷】【线段树】P1471 方差

    [题目背景:] 滚粗了的HansBug在收拾旧数学书,然而他发现了什么奇妙的东西. [题目描述:] 蒟蒻HansBug在一本数学书里面发现了一个神奇的数列,包含N个实数.他想算算这个数列的平均数和方差 ...

  7. 【洛谷】【线段树】P1047 校门外的树

    [题目描述:] 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,……,L ...

  8. 【洛谷】【线段树】P1886 滑动窗口

    [题目描述:] 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. [输入格式:] 输入一共 ...

  9. 【洛谷】【线段树】P3353 在你窗外闪耀的星星

    [题目描述:] /* 飞逝的的时光不会模糊我对你的记忆.难以相信从我第一次见到你以来已经过去了3年.我仍然还生动地记得,3年前,在美丽的集美中学,从我看到你微笑着走出教室,你将头向后仰,柔和的晚霞照耀 ...

随机推荐

  1. JDBCTemplate基本使用

    用了jdbc连接池之后,我们会发现连接对象的复用性更高了,程序整体运行的性能也更高了.但是我们在做JDBC操作的时候还是比较麻烦,要定义sql,执行sql,设置参数,处理结果. 特别是当我们要做查询操 ...

  2. 给小米路由R1D增加WebDAV服务

    我的R1D是14年买的,原装的硬盘已经不能用了,换了一块从笔记本上退役下来的500G硬盘后继续愉快的使用了-- 当初买这款路由器的原因之一是看中了它的内置硬盘,可以用来备份手机相册.存储智能摄像机录像 ...

  3. 想玩转JAVA高并发,这些概念你必须懂

    高并发高并发 它是互联网分布式系统架构设计中必须考虑的因素之一,通常是指,保证系统能够同时并行化处理海量请求 同步和异步 同步:发送一个请求,等待返回,然后再发送下一个请求.提交请求 -> 等待 ...

  4. 《Docker基础与实战,看这一篇就够了》

    什么是Docker? Docker 使用 Google 公司推出的 Go 语言 进行开发实现,基于 Linux 内核的 cgroup,namespace,以及 AUFS 类的 Union FS 等技术 ...

  5. ORA-19504: failed to create file "/u01/backup/db_0_20190603_1" ORA-27038: created file already exists

    1.问题:在用rman进行0级备份时,报错: ORA-19504: failed to create file "/u01/backup/db_0_20190603_1"ORA-2 ...

  6. SpringBoot_登录注册

    学习SpringBoot需要的前期基础 Spring(Bean容器 IOC set 构造方法 AOP) SpringMVC(GET POST Restful) 对于SpringBoot,约定大于配置 ...

  7. 服务器硬件和RAID配置

    服务器 硬件和RAID配置 目录 一.RAID 磁盘阵列介绍 1.1.RAID 0(条带化存储) 1.2.RAID 1(镜像存储) 1.3.RAID 5 1.4.RAID 6 1.5.RAID 1+0 ...

  8. 『心善渊』Selenium3.0基础 — 9、使用Seleniun中的By类定位元素

    目录 1.使用By定位的前提 2.By定位的方法 3.By定位的使用 4.复数形式的示例 我们还可以通过Seleniun测试框架中的By类,来实现页面中的元素定位. 1.使用By定位的前提 需要导入B ...

  9. Android Studio用上Visual Studio Android Emulator

    背景介绍 第一次接触Android官方的AVD(Android Virtual Device)时你可能会吐槽又慢又丑,不要紧,微软作为新晋安卓阵营最佳开发商,其实也为我们准备了一个脱胎于Windows ...

  10. Git&Gitlab开发流程与运维管理

    Git&Gitlab开发流程与运维管理 作者 刘畅 时间 2020-10-31 实验系统版本centos7.5 主机名称 ip地址 配置 安装软件 controlnode 172.16.1.1 ...