一种降低时间复杂度的空间储存方法。
对于一个数组 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; }