写了一下午的线段树,也算是做个总结吧。下面的区间更新写了两种,一种是没有用到懒操作一种是用了的。懒操作主要是在区间更新的时候用到,下面求区间和 and 区间最值都是要用到懒操作的
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int Max = 5e4;
int N,a[Max];
typedef struct Tree{
int L,R;
int sum;
int lazy;//需要增加的值
int Max;
};
Tree tree[Max<<2];
typedef long long ll;
void push_up(int x)
{
tree[x].sum = tree[x<<1].sum+tree[x<<1|1].sum;
tree[x].Max = max(tree[x<<1].Max,tree[x<<1|1].Max);
}
void push_down(int x,int num)
{
if(tree[x].lazy){
tree[x<<1].sum+=tree[x].lazy*(num-(num/2));//每个点需要更新的值*个数
tree[x<<1|1].sum += tree[x].lazy*(num/2);
tree[x<<1].Max = tree[x].Max+tree[x].lazy;
tree[x<<1|1].Max = tree[x].Max+tree[x].lazy;
tree[x<<1].lazy += tree[x].lazy;
tree[x<<1|1].lazy+=tree[x].lazy;
tree[x].lazy = 0;
}
}
void build(int x,int l,int r)
{
tree[x].L = l;
tree[x].R = r;
tree[x].sum = 0;
tree[x].lazy=0;
if(l==r){
tree[x].sum=a[l];
tree[x].Max=a[l];
return;
}
int mid = (l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
push_up(x);
}
void update(int x,int pos,int val)
{
int L = tree[x].L,R=tree[x].R;
if(L==R)
{
tree[x].sum += val;
tree[x].Max += val;
return;
}
int mid = (L+R)>>1;
if(pos<=mid)
update(x<<1,pos,val);
else
update(x<<1|1,pos,val);
push_up(x);
}
void update2(int x,int l,int r,int val)//将区间[l,r]的值都加上val【区间更新】
{
int L = tree[x].L,R=tree[x].R;
if(L==R){
tree[x].sum+=val;
tree[x].Max+=val;
return;
}
int mid = (L+R)>>1;
if(l<=mid){
update2(x<<1,l,r,val);
}
if(mid<r){
update2(x<<1|1,l,r,val);
}
push_up(x);
}
void update3(int x,int l,int r,int val)
{
int L= tree[x].L,R=tree[x].R;
if(l<=L&&r>=R){
tree[x].lazy+=val;
tree[x].Max+=val;
tree[x].sum += (ll)val*(R-L+1);
return;
}
push_down(x,R-L+1);
int mid = (L+R)>>1;
if(l<=mid) update3(x<<1,l,r,val);
if(mid<r) update3(x<<1|1,l,r,val);
push_up(x);
}
int query(int x,int l,int r)//区间和查询
{
int ans = 0;
int L = tree[x].L, R = tree[x].R;
if(l<=L&&r>=R)
return tree[x].sum;
push_down(x,R-L+1);
int mid = (l+r)>>1;
if(l<=mid)
ans+=query(x<<1,l,r);
if(mid<r)
ans+=query(x<<1|1,l,r);
return ans;
}
int searchMax(int x,int l,int r)//区间最值查询
{
int L = tree[x].L,R = tree[x].R;
if(l<=L&&R<=r){
return tree[x].Max;
}
push_down(x,R-L+1);
int mid = (l+r)>>1;
int res = -99999;
if(l<=mid) res=max(res,searchMax(x<<1,l,r));
if(mid<r) res = max(res,searchMax(x<<1|1,l,r));
return res;
}
int main()
{
string str;
scanf("%d",&N);
for(int i=1;i<=N;i++)
scanf("%d",&a[i]);
build(1,1,N);
while(1)
{
cin>>str;
if(str[0]=='e')
break;
else if(str[0]=='1'){//单点更新
int pos,val;
scanf("%d%d",&pos,&val);
update(1,pos,val);
}else if(str[0]=='2'){//不用懒标记的区间更新
int l,r,val;
scanf("%d%d%d",&l,&r,&val);
update2(1,l,r,val);
}else if(str[0]=='3'){//使用懒标记的区间更新
int l,r,val;
scanf("%d%d%d",&l,&r,&val);
update3(1,l,r,val);
}else if(str[0]=='4'){//区间最值查询
int l,r;
scanf("%d%d",&l,&r);
int ans = searchMax(1,l,r);
printf("%d
",ans);
}else{//query
int left,right;
scanf("%d%d",&left,&right);
int ans = query(1,left,right);
printf("%d
",ans);
}
}
return 0;
}
用了懒标记的和没有用懒标记的不要混在一起使用。