博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【洛谷P1816 忠诚】线段树
阅读量:5238 次
发布时间:2019-06-14

本文共 2902 字,大约阅读时间需要 9 分钟。

题目描述

老管家是一个聪明能干的人。他为财主工作了整整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 
#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;}

转载于:https://www.cnblogs.com/Dawn-Star/p/9782076.html

你可能感兴趣的文章
eclipse好用的快捷键
查看>>
BZOJ 2434: [Noi2011]阿狸的打字机( AC自动机 + DFS序 + 树状数组 )
查看>>
BZOJ 2005: [Noi2010]能量采集( 数论 + 容斥原理 )
查看>>
如何确定 原型与实例之间的关系
查看>>
Ruby and gnuplot installation on Ubuntu 16.04
查看>>
Windows 10 IoT Serials 8 – 如何改变UWP应用的目标平台
查看>>
java正则表达式语法详解及其使用代码实例
查看>>
第一阶段冲刺08
查看>>
.net webservers的使用
查看>>
数据库快照
查看>>
程序员修炼之道-笔记
查看>>
iOS10遇到有推送的Demo真机报错的解决
查看>>
在liferay中如何使用Ajax的请求
查看>>
liferay中如何获取实例的id和portletId
查看>>
LeetCode_Binary Tree Maximum Path Sum
查看>>
web框架UI系列--MVC常用控件讲解一
查看>>
整理小朋友在noi.openjudge上的作业(3)
查看>>
Educational Codeforces Round 30 B【前缀和+思维/经典原题】
查看>>
The Solution of UESTC 2016 Summer Training #1 Div.2 Problem A
查看>>
js检测服务器端Seesion是否存在
查看>>