一种降低时间复杂度的空间储存方法。
对于一个数组 a[N](这里N=16)
可以采取线段树 tr[N] 的方式储存
方便进行 单点修改、区间查询。
样式图:(1—16:表示存一个在1~16这个区间内的属性)
1———————16 | |||||||||||||||
1 —— 8 | 9——16 | ||||||||||||||
1——4 | 5——8 | 9——12 | 13——16 | ||||||||||||
1——2 | 3——4 | 5——6 | 7——8 | 9——10 | 11——12 | 13——14 | 14——16 | ||||||||
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
接下来是一个完整版子
// main.cpp
// 线段树
//区间最大值线段树
#include <iostream>
#include <cstring>
#include <math.h>
using namespace std;
#define N 10001
int tr[N*4];//为了从 总数/2 处开始建立
//线段树建立
void build(int rt,int l,int r)
{
if(l==r)
{scanf("%d",&tr[rt]);return;}
int m=(l+r)/2;//取中间值
build(2*rt,l,m);//建立左子节点
build(2*rt+1,m+1,r);//建立右子节点
tr[rt]=max(tr[rt*2],tr[rt*2+1]);//取两个字节点的最大值
}
//更改某一节点的值
void charge(int rt,int l,int r,int u,int num)
{
if(r==l)
{tr[rt]=num;return;}
int m=(l+r)/2;
if(u<=m) charge(2*rt,l,m,u,num);//完善左节点
else charge(2*rt+1,m+1,r,u,num);//完善右节点
tr[rt]=max(tr[rt*2],tr[rt*2+1]);//完善树
}
//查找区间最大值
int max_of_query(int rt,int l,int r,int L,int R)
{
if(L==l && R==r)//判断整体在不在一个完整的区间里
return tr[rt];//返回该区间的值
int m=(r+l)/2;
int maxl=0;//定义最大值
if(L<=m)
{
if(R>m)//判断右端点是否在区间内
maxl=max(maxl,max_of_query(rt*2,l,m,L,m));
else
maxl=max(maxl,max_of_query(rt*2,l,m,L,R));
}//左子区间
if(R>=m+1)
{
if(L<m+1)//同上
maxl=max(maxl,max_of_query(rt*2+1,m+1,r,m+1,R));
else
maxl=max(maxl,max_of_query(rt*2+1,m+1,r,L,R));
}//右子区间
return maxl;
}
//生成树
void see_tree(int tr[])
{
int i,j=1;
for(i=1;tr[i]!=0;i++)
{
if(i==pow(2,j))
{printf("\n");j++;}
printf("%d\t",tr[i]);
}
}
int main()
{
int n;
int u,num;
int l,r,mx;
cin>>n;
build(1,1,n);//建立一个从1~n的最大值线段树
see_tree(tr);
cin>>u>>num;//改位置u上的数为num
charge(1,1,n,u,num);
see_tree(tr);
cin>>l>>r;//查找区间(l,r)最大值
mx=max_of_query(1,1,n,l,r);
printf("%d",mx);
//see_tree(tr);
return 0;
}