线段树讲解
线段树模板1
参考题解:
#include
#include
using namespace std;
#define maxn 100010
typedef struct node{
int l;//左孩子
int r;//右孩子
long long num;//维护的值
long long lz;//懒惰标记
}tree;
tree t[4*maxn+2];
int a[maxn+2];
void build(int index,int left,int right)//建树
{
t[index].l=left;t[index].r=right;
if(left==right) {t[index].num=a[left]; return;}
int mid=(left+right)>>1;
build(2*index,left,mid);
build(2*index+1,mid+1,right);
t[index].num=t[2*index].num+t[2*index+1].num;
}
void spread(int p)//懒标记下放
{
if(t[p].lz!=0)
{
t[2*p].num+=(t[2*p].r-t[2*p].l+1)*t[p].lz;//对左孩子的值进行更新,一起加上num
t[2*p+1].num+=(t[2*p+1].r-t[2*p+1].l+1)*t[p].lz;//对右孩子的值进行更新,一起加上num
t[2*p].lz+=t[p].lz;//懒标记下放
t[2*p+1].lz+=t[p].lz;
t[p].lz=0;//消除懒标记
}
}
void change(int p,int x,int y,int k)//区间修改
{
if(x<=t[p].l&&y>=t[p].r)//在区间内,直接修改。比如说一共有[1,10];然后左边是[1,5],要修改[1,5],查询的时候刚好是这个区间,就对这个区间进行更改然后下放标签
{
t[p].num+=(t[p].r-t[p].l+1)*k;
t[p].lz+=k;
return ;
}
//如果不是完全涵盖在这个区间,就要向下寻找,可能有以前标记的懒标签,要一起下放
spread(p);//上次的懒标记下放
int mid=(t[p].l+t[p].r)>>1;//除以2
if(x<=mid) change(2*p,x,y,k);//查询左区间
if(y>=mid+1) change(2*p+1,x,y,k);//查询右区间
t[p].num=t[2*p].num+t[2*p+1].num;//回溯的时候记得进行更改
}
long long ask(int p,int x,int y)//区间查询,询问这个区间的和
{
if(x<=t[p].l&&y>=t[p].r) return t[p].num;
spread(p);
int mid=(t[p].l+t[p].r)>>1;
long long ans=0;
if(x<=mid) ans+=ask(2*p,x,y);
if(y>=mid+1) ans+=ask(2*p+1,x,y);
return ans;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,1,n);
for(int i=1;i<=m;i++)
{
int q,x,y,z;
scanf("%d",&q);
if(q==1){
scanf("%d%d%d",&x,&y,&z);
change(1,x,y,z);
}
else {
scanf("%d%d",&x,&y);
cout<<ask(1,x,y)<<endl;
}
}
return 0;
}
添加链接描述
线段树模板2
有加法有乘法
#include
#include
using namespace std;
#define maxn 100010
int n,m,mod;
#define ll long long
typedef struct node{
ll l,r,num,mu,add;
}tree;
tree t[4*maxn+2];
int a[maxn+2];
ll read(){
ll x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return x;
}
void build(ll index,ll left,ll right)//建树
{
t[index].l=left;t[index].r=right;t[index].mu=1;
if(left==right) {t[index].num=a[left]%mod; return;}
ll mid=(left+right)>>1;
build(2*index,left,mid);
build(2*index+1,mid+1,right);
t[index].num=(t[2*index].num+t[2*index+1].num)%mod;
}
void spread(ll p)//懒标记下放
{
t[2*p].num=(t[p].mu*t[2*p].num+((t[2*p].r-t[2*p].l+1)*t[p].add)%mod)%mod;//对左孩子的值进行更新,一起加上num
t[2*p+1].num=(t[p].mu*t[2*p+1].num+((t[2*p+1].r-t[2*p+1].l+1)*t[p].add)%mod)%mod;//对右孩子的值进行更新,一起加上num
t[2*p].add=(t[p].add+t[2*p].add*t[p].mu)%mod;//懒标记下放
t[2*p+1].add=(t[p].add+t[2*p+1].add*t[p].mu)%mod;
t[2*p].mu=t[2*p].mu*t[p].mu%mod;//懒标记下放
t[2*p+1].mu=t[2*p+1].mu*t[p].mu%mod;
t[p].add=0;
t[p].mu=1;//消除懒标记
}
void addchange(ll p,ll x,ll y,ll k)//区间修改
{
if(x<=t[p].l&&y>=t[p].r)//在区间内,直接修改。比如说一共有[1,10];然后左边是[1,5],要修改[1,5],查询的时候刚好是这个区间,就对这个区间进行更改然后下放标签
{
t[p].num=(t[p].num+(t[p].r-t[p].l+1)*k)%mod;
t[p].add=(t[p].add+k)%mod;
return ;
}
//如果不是完全涵盖在这个区间,就要向下寻找,可能有以前标记的懒标签,要一起下放
spread(p);//上次的懒标记下放
//t[p].num=(t[p*2].num+t[p*2+1].num)%mod;
ll mid=(t[p].l+t[p].r)>>1;//除以2
if(x<=mid) addchange(2*p,x,y,k);//查询左区间
if(y>=mid+1) addchange(2*p+1,x,y,k);//查询右区间
t[p].num=(t[2*p].num+t[2*p+1].num)%mod;//回溯的时候记得进行更改
}
void mulchange(ll p,ll x,ll y,ll k)//区间修改
{
if(x<=t[p].l&&y>=t[p].r)//在区间内,直接修改。比如说一共有[1,10];然后左边是[1,5],要修改[1,5],查询的时候刚好是这个区间,就对这个区间进行更改然后下放标签
{
t[p].add=t[p].add*k%mod;
t[p].mu=t[p].mu*k%mod;
t[p].num=t[p].num*k%mod;
return ;
}
//如果不是完全涵盖在这个区间,就要向下寻找,可能有以前标记的懒标签,要一起下放
spread(p);//上次的懒标记下放
//t[p].num=(t[p*2].num+t[p*2+1].num)%mod;
ll mid=(t[p].l+t[p].r)>>1;//除以2
if(x<=mid) mulchange(2*p,x,y,k);//查询左区间
if(y>=mid+1) mulchange(2*p+1,x,y,k);//查询右区间
t[p].num=(t[2*p].num+t[2*p+1].num)%mod;//回溯的时候记得进行更改
}
long long ask(int p,int x,int y)//区间查询,询问这个区间的和
{
if(x<=t[p].l&&y>=t[p].r) return t[p].num;
spread(p);
int mid=(t[p].l+t[p].r)>>1;
long long ans=0;
if(x<=mid) ans=(ans+ask(2*p,x,y))%mod;
if(y>=mid+1) ans=(ans+ask(2*p+1,x,y))%mod;
return ans;
}
int main(){
cin>>n>>m>>mod;
for(int i=1;i<=n;i++){
a[i]=read();
}
build(1,1,n);
for(int i=1;i<=m;i++){
int ty=read();
if(ty==1){
long long cn=read(),cm=read(),cw=read();
mulchange(1,cn,cm,cw);
}else if(ty==2){
long long cn=read(),cm=read(),cw=read();
addchange(1,cn,cm,cw);
}else {
long long cn=read(),cm=read();
cout<<ask(1,cn,cm)%mod<<endl;
}
}
}