非叶子节点储存两个信息一是它的所有子孙叶子节点所在区间的最大值,二是所有子孙节点所在区间内的和。
明白了结构对于线段树的插入,更新·,操作就和普通树差不多。我们可以定义一个结构体来描述树的每个节点,然后用结构体数组描述整棵树的情况,从1开始为根节点,若节点在数组中编号为i,则它的左孩子节点的编号为2i,右孩子节点标号为2i+1.
#include
#include
#include
using namespace std;
int SUM,MAX;//用来记录所求区间内的和与最大值
struct SegTree
{
int left,right,Max,sum;//分别节点所代表的左右区间,最大值,和
}seq[1000001];
void init(int l,int r,int i)//初始化l表示左区间,r表右区间,i表示自己的原序列编号
{
seq[i].left=l;
seq[i].right=r;
seq[i].Max=0;
seq[i].sum=0;
if(l!=r)//如果没有到达叶子节点
{
int mid=(l+r)/2;
init(l,mid,2*i);//递归初始化左子树
init(mid+1,r,2*i+1);//递归初始化右子树
}
}
void insert(int i,int x,int m)//插入操作,i表示根节点编号,x表示要插入的点在原序列的编号,m表示要插入点的值
{
if(x>=seq[i].left&&x<=seq[i].right)//找到位置插入
{
seq[i].Max=m;
seq[i].sum=m;
}
if(seq[i].left==seq[i].right)//找到叶节点返回
return;
int mid=(seq[i].left+seq[i].right)/2;
if(x>mid)//如果序号在根的左区间,就把它往左子树上
insert(2*i+1,x,m);
else//如果序号在根的右区间,就把它往右子树上插入
insert(2*i,x,m);
seq[i].sum=seq[2*i].sum+seq[2*i+1].sum;//每一次插入后更新一下根节点的sum与max值
seq[i].Max=max(seq[2*i].Max,seq[2*i+1].Max);
}
int find_max(int x,int y,int i))//找最大值x,y表左右区间,i表节点编号
{
if(x==seq[i].left&&y==seq[i].right)//如果找到就返回最大值return
return seq[i].Max;
int mid=(seq[i].left+seq[i].right)/2;
if(x>mid)//如果x,y区间序号在i节点的区间的右侧,就再从右区间里找
return find_max(x,y,2*i+1);
else if(y<=mid)
return find_max(x,y,2*i);
else//如果x,y在i节点的区间内,那么就得从i节点的左右孩子节点内找一个最大值
return max(find_max(x,mid,2*i),find_max(mid+1,y,2*i+1));
}
int find_sum(int x,int y,int i)//与上面基本相同
{
if(x==seq[i].left&&y==seq[i].right)
return seq[i].sum;
int mid=(seq[i].left+seq[i].right)/2;
if(x>mid)
return find_sum(x,y,2*i+1);
else if(y<=mid)
return find_sum(x,y,2*i);
else
return find_sum(x,mid,2*i)+find_sum(mid+1,y,2*i+1);
}
int main()
{
int n,m,weight,p,x,y;
cin>>n>>m;
init(1,n,1);
for(int i=1;i<=n;i++)
{
cin>>weight;
insert(1,i,weight);
}
for(int i=0;i>p>>x>>y;
if(p==1)
insert(1,x,y);
if(p==2)
cout<