以下块代码线段数的查询过程:
很妙的就是本来数据是被放在一个正常不过的数组中,但是通过线段树的实现就将数据存到用一个特殊数组储存的线段树中了,你会发现存入以后不管是改值还是查询都于之前的那个正常的数组无关了,
那如何定位需要查询的范围呢?
以下就是通过rt来代表当前操作的位置,值得注意的是每次开始rt都是从1开始,然后左节点1*2,右节点1*2+1,如此反复即可遍历所有线段树,从而查询
int Query(int L,int R,int l,int r,int rt){//[L,R]表示操作区间,[l,r]表示当前区间,rt:当前节点编号
if(L <= l && r <= R){
//在区间内直接返回
return Sum[rt];
int m=(l+r)>>1;
//左子区间:[l,m] 右子区间:[m+1,r] 求和区间:[L,R]
//累加答案
int ANS=0;
if(L <= m) ANS+=Query(L,R,l,m,rt<<1);//左子区间与[L,R]有重叠,递归
if(R > m) ANS+=Query(L,R,m+1,r,rt<<1|1); //右子区间与[L,R]有重叠,递归
return ANS;
}
像上面的ans,如果要对ans在递归中实现求和操作,我们可以直接在函数中定义ans注意:千万不要在函数中另外加一个参数ans,这样会导致返回值就是初始化的
而且注意return 在这里上下都要有return !!!
像如下代码中search中的min1就不可以让其作为参数
min1不能像上面ans一样返回,就像下面的代码就好了
插入一个:
像下面maxn=1e5+5;c++中可以兼容,但是有的编译器会报错,1e5返回的是double,这种情况下int(1e5+5)即可
计蒜客线段树专题:”忠诚的管家“
老管家是一个聪明能干的人。他为财主工作了整整10年,财主为了让自已账目更加清楚。要求管家每天记k次账,由于管家聪明能干,因而管家总是让财主十分满意。但是由于一些人的挑拨,财主还是对管家产生了怀疑。于是他决定用一种特别的方法来判断管家的忠诚,他把每次的账目按1,2,3…编号,然后不定时的问管家问题,问题是这样的:在a到b号账中最少的一笔是多少?为了让管家没时间作假他总是一次问多个问题。
输入中第一行有两个数m,n表示有m(m< =100000)笔账,n表示有n个问题,n< =100000。 第二行为m个数,分别是账目的钱数 后面n行分别是n个问题,每行有2个数字说明开始结束的账目编号。
输出文件中为每个问题的答案。具体查看样例。
样例输入复制
10 3 1 2 3 4 5 6 7 8 9 10 2 7 3 9 1 10样例输出复制
2 3 1
#include "bits/stdc++.h"
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define inf 1e9+5
using namespace std;
const int maxn = 1e5+5;
int a[maxn],tree[maxn<<2];
int m,n,min1;
void pushup(int rt)
{
int min1=min(tree[rt<<1],tree[rt<<1|1]);
tree[rt]=min1;
}
void build(int l,int r,int rt)
{
if(l==r)
{
tree[rt]=a[l];
return;
}
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
pushup(rt);
}
int search(int L,int R,int l,int r,int rt)//L,R表示当前大小
{
if(l<=L&&r>=R)
{
min1 = min(min1,tree[rt]);
return min1;
}
int m = (L+R)>>1;
if(m>=l) search(L,m,l,r,rt<<1);
if(m<r) search(m+1,R,l,r,rt<<1|1);
return min1;
}
int main()
{
cin>>n>>m;
rep(i,1,n)
cin>>a[i];
build(1,n,1);
int a1[maxn],b1[maxn];
int ans[maxn];
rep(i,1,m)
{
cin>>a1[i]>>b1[i];
min1=inf;
ans[i]=search(1,n,a1[i],b1[i],1);
}
rep(i,1,m)
{
cout<<ans[i];
if(i!=m)
cout<<" ";
}
return 0;
}