下面的两份线段树模板,一份是单点更新维护区间最小值,一份是区间更新,同时维护区间和,区间最大最小值。
代码如下:
///线段树单点更新
#include<iostream>
#include<cstdio>
#include<cstring>
#include<fstream>
using namespace std;
#define maxn 1000
#define INF 0x3f3f3f3f
int a[maxn];
int minv[maxn*4]; ///线段树标记数组
///线段树构造函数
///其实就是要找到相应线段在线段树中的编号
///然后记录一下信息(形参表示编号为o的线段树节点对应的线段是L--R)
void build(int o,int L,int R)
{
int M=L+(R-L)/2;
if(L==R)
minv[o]=a[L];
else
{
build(2*o,L,M);
build(2*o+1,M+1,R);
minv[o]=min(minv[2*o],minv[2*o+1]);
}
}
///单点更新 更新a[p]的值为v
///先找到这个点在线段树中对应的编号,更新
///然后再递归向上更新
void update(int o,int L,int R,int p,int v)
{
int M=L+(R-L)/2;
if(L==R)
minv[o]=v;
else
{
if(p<=M)
update(o*2,L,M,p,v);
else
update(o*2+1,M+1,R,p,v);
minv[o]=min(minv[2*o],minv[2*o+1]);
}
}
///区间查询 查询区间ql,qr之间的最小值
int query(int o,int L,int R,int ql,int qr)
{
int ans=INF; int M=L+(R-L)/2;
///当前区间完全被待查询区间包含
if(ql<=L&&qr>=R)
return minv[o];
if(ql<=M) ///查询区间与左区间有交点
ans=min(ans,query(o*2,L,M,ql,qr));
if(qr>M) ///查询区间与右区间有交点
ans=min(ans,query(2*o+1,M+1,R,ql,qr));
return ans;
}
int main()
{
int n;
ifstream fin("lkl.txt");
while(fin>>n)
{
for(int i=1;i<=n;i++)
fin>>a[i];
build(1,1,n);
cout<<query(1,1,n,2,5)<<endl; ///查询a[1,n]中的最小值
update(1,1,n,3,-1); ///修改a[3]=-1
cout<<query(1,1,n,2,5)<<endl; ///查询a[1,n]中的最小值
}
return 0;
}
///线段树区间更新加维护 区间最大值 最小值 区间和
#include<iostream>
#include<cstdio>
#include<cstring>
#include<fstream>
using namespace std;
#define INF 0x3f3f3f3f
#define maxn 1000
int a[maxn],sum[maxn*4],minv[maxn*4];
///每个节点都会被附加一个lazy标记
int lazy[maxn*4],maxv[maxn*4];
///更新子节点后维护父节点信息
void maintain(int o,int L,int R)
{
int lc=2*o,rc=2*o+1;
sum[o]=sum[lc]+sum[rc];
minv[o]=min(minv[lc],minv[rc]);
maxv[o]=max(maxv[lc],maxv[rc]);
}
///递归查询或者修改时向下传递信息
void pushdown(int o,int L,int R)
{
int lc=2*o,rc=2*o+1,M=(L+R)/2;
///如果当前父节点有lazy标记的话就传递给它的儿子节点
if(lazy[o]!=INF)
{
sum[lc]+=lazy[o]*(M-L+1);
sum[rc]+=lazy[o]*(R-M);
minv[lc]+=lazy[o];
maxv[lc]+=lazy[o];
minv[rc]+=lazy[o];
maxv[rc]+=lazy[o];
if(lazy[2*o]==INF)
lazy[2*o]=lazy[o];
else
lazy[2*o]+=lazy[o];
if(lazy[2*o+1]==INF)
lazy[2*0+1]=lazy[o];
else
lazy[2*o+1]+=lazy[o];
lazy[o]=INF; ///传递完成后就将父节点的标记清除
}
}
void build(int o,int L,int R)
{
int M=L+(R-L)/2;
if(L==R)
{
sum[o]=a[L];
minv[o]=a[L];
maxv[o]=a[L];
}
else
{
build(2*o,L,M);
build(2*o+1,M+1,R);
maintain(o,L,R);
}
}
void update(int o,int L,int R,int ql,int qr,int add)
{
int M=L+(R-L)/2;
if(ql<=L&&qr>=R)
{
sum[o]+=(R-L+1)*add;
minv[o]+=add;
maxv[o]+=add;
if(lazy[o]==INF)
lazy[o]=add;
else
lazy[o]+=add;
return ;
}
pushdown(o,L,R);
if(ql<=M)
update(o*2,L,M,ql,qr,add);
if(qr>M)
update(2*o+1,M+1,R,ql,qr,add);
maintain(o,L,R);
}
///定义全局变量用来记录当前区间查询的结果
int _max,_min,_sum;
void query(int o,int L,int R,int ql,int qr)
{
int M=L+(R-L)/2;
if(ql<=L&&qr>=R)
{
_sum+=sum[o];
_max=max(_max,maxv[o]);
_min=min(_min,minv[o]);
return ;
}
pushdown(o,L,R);
if(ql<=M)
query(2*o,L,M,ql,qr);
if(qr>M)
query(2*o+1,M+1,R,ql,qr);
}
void Init()
{
_max=0,_min=INF,_sum=0;
}
void print(int x,int y)
{
cout<<x<<" "<<y<<endl;
cout<<_max<<" "<<_min<<" "<<_sum<<endl;
}
int main()
{
int n;
ifstream fin("lkl.txt");
while(fin>>n)
{
memset(lazy,0x3f,sizeof(lazy));
for(int i=1;i<=n;i++)
fin>>a[i];
build(1,1,n);
Init();
query(1,1,n,1,1); ///查询a[1,n]中的最小值,最大值,区间和
print(2,5);
update(1,1,n,2,2,-1); ///a[2,5]中的所有元素都减1
Init();
query(1,1,n,2,2); ///查询a[2,5]中的最小值,最大值,区间和
print(2,5);
Init();
update(1,1,n,4,4,4); ///查询a[2,5]中的最小值,最大值,区间和
query(1,1,n,4,4);
print(2,5);
}
return 0;
}
原文:http://blog.csdn.net/acm_lkl/article/details/44631807