线段树模板(有注释)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define N 100000
using namespace std;
int a[N],Sum[N<<2],Add[N<<2];//开4倍大的数组构建线段树
void Pushup(int rt){Sum[rt]=Sum[rt<<1]+Sum[rt<<1|1];}//向上传值
void PushDown(int rt,int ln,int rn)//向下传懒标记并更新值,ln为左子树结点数,rn为右子树结点数
{
if(Add[rt])//当懒标记不为0时
{
Add[rt<<1]+=Add[rt];//将懒标记传给左孩子
Add[rt<<1|1]+=Add[rt];//将懒标记传给右孩子
Sum[rt<<1]+=Add[rt]*ln;//更新左子树的值
Sum[rt<<1|1]+=Add[rt]*rn;//更新右子树的值
Add[rt]=0;//将当前结点的懒标记置为0
}
}
void Build(int l,int r,int rt)//建树
{
if(l==r)//遍历到叶结点时直接存数据
{
Sum[rt]=a[l];
return ;
}
int m=(l+r)>>1;
Build(l,m,rt<<1);//建左子树
Build(m+1,r,rt<<1|1);//建右子树
Pushup(rt);//向上传值
}
void Update1(int L,int C,int l,int r,int rt)//点修改,a[L]+=C
{
if(l==r)//当为叶节点时直接更新结点的值
{
Sum[rt]+=C;
return ;
}
int m=(l+r)>>1;
if(L<=m)Update1(L,C,l,m,rt<<1);//若结点在左子树,更新左子树
else Update1(L,C,m+1,r,rt<<1|1);//若结点在右子树,更新右子树
Pushup(rt);//向上传值
}
void Update2(int L,int R,int C,int l,int r,int rt)//区间修改
{
if(L<=l&&R>=r)//当要修改的区间覆盖结点区间时,当前结点Sum值直接加上结点数*C
{
Sum[rt]+=C*(r-l+1);
Add[rt]+=C;
return ;
}
int m=(l+r)>>1;
PushDown(rt,m-l+1,r-m);//向下传递懒标记并更新值
if(L<=m)Update2(L,R,C,l,m,rt<<1);//更新左子树
if(R>m)Update2(L,R,C,m+1,r,rt<<1|1);//更新右子树
Pushup(rt);//向上传值
}
int Query(int L,int R,int l,int r,int rt)//区间访问
{
if(L<=l&&R>=r)//当要修改的区间覆盖结点区间时,直接访问
{
return Sum[rt];
}
int m=(l+r)>>1;
PushDown(rt,m-l+1,r-m);//避免懒标记没有处理
int ans=0;
if(L<=m)ans+=Query(L,R,l,m,rt<<1);//返回左子树的值
if(R>m)ans+=Query(L,R,m+1,r,rt<<1|1);//返回右子树的值
return ans;
}
int Findmax(int L,int R,int l,int r,int rt)//查询区间最大值,是找最大值的区间,即最长的线段
{
if(L<=l&&R>=r)//当要修改的区间覆盖结点区间时,直接访问
{
return Sum[rt];
}
int m=(l+r)>>1;
int ans=0;
if(L<=m)ans=max(ans,Findmax(L,R,l,m,rt<<1));//求左子树最大值区间
if(R>m)ans=max(ans,Findmax(L,R,m+1,r,rt<<1|1));//求右子树最大值区间
return ans;
}
int main()
{
int n,ope,L,C,R;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
Build(1,n,1);//建树
while(cin>>ope)
{
if(ope==0)break;//退出循环
else if(ope==1)//点修改
{
cin>>L>>C;
Update1(L,C,1,n,1);
cout<<"结点"<<L<<"修改成功"<<endl;
}
else if(ope==2)//区间修改
{
cin>>L>>R>>C;
Update2(L,R,C,1,n,1);
cout<<"区间"<<L<<'——'<<R<<"修改成功"<<endl;
}
else if(ope==3)//区间访问
{
cin>>L>>R;
cout<<"区间"<<L<<"——"<<R<<"的值为"<<Query(L,R,1,n,1)<<endl;
}
else if(ope==4)//查询区间最大值
{
cin>>L>>R;
cout<<"区间"<<L<<"——"<<R<<"的最大值为"<<Findmax(L,R,1,n,1)<<endl;
}
}
return 0;
}