不会基础先学这个线段树基础
我们以P3373 【模板】线段树 2来开始讲
简单来说题目是让我们执行3个操作:
区间加、区间乘,区间查询。
就是要用两个懒标记——一个add加法懒标记、一个mul乘法懒标记。
只有一点点与原来不一样。
更新懒标记时:
mul=mul*new_mul;
add=add*new_mul+new_add;
sum更新:
sum=sum*new_mul+(r-l+1)*new_add;
上代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define F(i,a,b) for(int i=a;i<=b;i++)
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
const int N=1e6+5;
int a[N],sum[N<<2],lazy_add[N<<2],lazy_mul[N<<2];
int n,q,mod,op,x,y,k;
void pushup(int k)
{
sum[k]=sum[ls(k)]+sum[rs(k)];
return;
}
void update_son(int k,int l,int r,int add,int mul)//懒标记下放
{
lazy_mul[k]*=mul;
lazy_mul[k]%=mod;
lazy_add[k]=lazy_add[k]*mul+add;
lazy_add[k]%=mod;
sum[k]*=mul;
sum[k]%=mod;
sum[k]+=(r-l+1)*add;
sum[k]%=mod;
return;
}
void pushdown(int k,int l,int r)
{
int mid=(l+r)>>1;
update_son(ls(k),l,mid,lazy_add[k],lazy_mul[k]);
update_son(rs(k),mid+1,r,lazy_add[k],lazy_mul[k]);
lazy_add[k]=0;
lazy_mul[k]=1;
return;
}
void build(int k,int l,int r)
{
lazy_add[k]=0;
lazy_mul[k]=1;
if(l==r)
{
sum[k]=a[l];
return;
}
int mid=(l+r)>>1;
build(ls(k),l,mid);
build(rs(k),mid+1,r);
pushup(k);
return;
}
int query(int L,int R,int k,int l,int r)
{
if(L<=l&&r<=R)
{
return sum[k];
}
int res=0;
int mid=(l+r)>>1;
pushdown(k,l,r);
if(L<=mid)
{
res+=query(L,R,ls(k),l,mid);
res%=mod;
}
if(R>mid)
{
res+=query(L,R,rs(k),mid+1,r);
res%=mod;
}
return res;
}
void update(int L,int R,int add,int mul,int k,int l,int r)
{
if(L<=l&&r<=R)
{
update_son(k,l,r,add,mul);
return;
}
int mid=(l+r)>>1;
pushdown(k,l,r);
if(L<=mid)
{
update(L,R,add,mul,ls(k),l,mid);
}
if(R>mid)
{
update(L,R,add,mul,rs(k),mid+1,r);
}
pushup(k);
return;
}
signed main()
{
cin>>n>>q>>mod;
F(i,1,n)
{
cin>>a[i];
}
build(1,1,n);
while(q--)
{
cin>>op;
if(op==1)
{
cin>>x>>y>>k;
update(x,y,0,k,1,1,n);
}
if(op==2)
{
cin>>x>>y>>k;
update(x,y,k,1,1,1,n);
}
if(op==3)
{
cin>>x>>y;
cout<<query(x,y,1,1,n)<<'\n';
}
}
return 0;
}
练练手
P1253 扶苏的问题
简单来说题目是让我们执行3个操作:
区间加、区间赋值,区间查询。
赋值可以当成乘0加k。
完整代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define F(i,a,b) for(int i=a;i<=b;i++)
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define INF 1e18
const int N=(1e6+7);
int a[N],t[N<<2],lazy_add[N<<2],lazy_mul[N<<2];
int n,q,op,x,y,k;
void pushup(int k)
{
t[k]=max(t[ls(k)],t[rs(k)]);
return;
}
void update_son(int k,int l,int r,int add,int mul)
{
lazy_mul[k]*=mul;
lazy_add[k]=lazy_add[k]*mul+add;
t[k]*=mul;
t[k]+=add;
return;
}
void pushdown(int k,int l,int r)
{
int mid=(l+r)>>1;
update_son(ls(k),l,mid,lazy_add[k],lazy_mul[k]);
update_son(rs(k),mid+1,r,lazy_add[k],lazy_mul[k]);
lazy_add[k]=0;
lazy_mul[k]=1;
return;
}
void build(int k,int l,int r)
{
lazy_add[k]=0;
lazy_mul[k]=1;
if(l==r)
{
t[k]=a[l];
return;
}
int mid=(l+r)>>1;
build(ls(k),l,mid);
build(rs(k),mid+1,r);
pushup(k);
return;
}
int query(int L,int R,int k,int l,int r)
{
if(L<=l&&r<=R)
{
return t[k];
}
int res=-1e18;
int mid=(l+r)>>1;
pushdown(k,l,r);
if(L<=mid)
{
res=max(res,query(L,R,ls(k),l,mid));
}
if(R>mid)
{
res=max(res,query(L,R,rs(k),mid+1,r));
}
return res;
}
void update(int L,int R,int add,int mul,int k,int l,int r)
{
if(L<=l&&r<=R)
{
update_son(k,l,r,add,mul);
return;
}
int mid=(l+r)>>1;
pushdown(k,l,r);
if(L<=mid)
{
update(L,R,add,mul,ls(k),l,mid);
}
if(R>mid)
{
update(L,R,add,mul,rs(k),mid+1,r);
}
pushup(k);
return;
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>q;
F(i,1,n)
{
cin>>a[i];
}
build(1,1,n);
while(q--)
{
cin>>op;
if(op==1)
{
cin>>x>>y>>k;
update(x,y,k,0,1,1,n);
}
if(op==2)
{
cin>>x>>y>>k;
update(x,y,k,1,1,1,n);
}
if(op==3)
{
cin>>x>>y;
cout<<query(x,y,1,1,n)<<'\n';
}
}
return 0;
}