【洛谷P1816 忠诚】线段树
題目描述
老管家是一個聰明能干的人。他為財主工作了整整10年,財主為了讓自已賬目更加清楚。要求管家每天記k次賬,由于管家聰明能干,因而管家總是讓財主十分滿意。但是由于一些人的挑撥,財主還是對管家產生了懷疑。于是他決定用一種特別的方法來判斷管家的忠誠,他把每次的賬目按1,2,3…編號,然后不定時的問管家問題,問題是這樣的:在a到b號賬中最少的一筆是多少?為了讓管家沒時間作假他總是一次問多個問題。
分析
關于線段樹的詳細講解可以參考拙作(點擊傳送門):【算法微解讀】淺談線段樹
那么我們就開始講解一下這一道模板題,題目的主要意思就是區間查詢最小值。
首先定義線段樹的節點的狀態segment_tree_node
接下來就是建樹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;//取中間midbuild(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的。
那么我們通過代碼來詳細的看一下區間查詢最小值是如何寫的。
主程序就不寫了,也是很簡單的
恒定義: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;//取中間midbuild(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
總結
以上是生活随笔為你收集整理的【洛谷P1816 忠诚】线段树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: js Array Map and Set
- 下一篇: touch创建文件