线段树的性质
1.定义时要开4倍空间
struct tree{
long long lazy,s;
long long maxx,minn;
}t[N<<2];
注意别 <<4 容易 MLE 是<<2
4倍空间原因
2.左右儿子
ll ls(ll p){ return p<<1;}
ll rs(ll p){ return p<<1|1;}
3.建树
void build(ll p,ll l, ll r){
//t[p],l=l,t[p].r=r;一般没用
t[p].add=0,t[p].mu=1;
//add 加的懒惰标记
//mu 乘的懒惰标记
if(l==r){ t[p].sum=num[l];return ; }
ll mid=l+(r-1)>>1;
//防止爆long long 或者 int
build(ls(p),l,mid),build(rs(p),mid+1,r);
push_up_sum(p);
//访问到根节点时回溯,向上建树
}
4. 维护区间的和(最大值/最小值)
void push_up_sum(ll p){
return t[p].s= t[ls(p)].s + t[rs(p)].s;
}
void push_up_max(ll p){
t[p].maxx=max(t[ls(p)].maxx,t[rs(p)].maxx);
}
void push_up_min(ll p){
t[p].minn=min(t[ls(p)].minn,t[rs(p)].minn);
}
5.区间加与区间乘同时进行(PS:其实加也可以是减,因为输入的K如果是负数,会按照负数进行加)
void mu(ll p,ll L,ll R,ll l,ll r,ll k){
if(l<=L&&R<=r){
t[p].sum=t[p].sum*k%mod;
t[p].mu=t[p].mu*k%mod;
t[p].add=t[p].add*k%mod;
return ;}
push_down(p,L,R);
ll mid=L+(R-1)>>1;
if(l<=mid) mu(ls(p),L,mid,l,r,k);
if(mid<r) mu(rs(p),mid+1,R,l,r,k);
push_up_sum(p);
//最后一定要更新树的值(回溯时完成)
}
void add(ll p,ll L,ll R,ll l,ll r,ll k){
if(l<=L&&R<=r){
t[p].add = (t[p].add+k);
t[p].sum = t[p].sum + k*(R-L+1);
return;
}
push_down(p,L,R);
ll mid = L+(R-1)>>1;
if(l<=mid) add(ls(p),L,mid,l,r,k);
if(mid<r) add(rs(p),mid+1,R,l,r,k);
push_up_sum(p);
//同理,最后一定要更新树的值(回溯时完成)
}
其实这里没什么区别都是只要在P的区间L-->R位于要更新的l->r的区间内,那么就懒惰处理,区间和的更改(进行数学计算)
6.重点!push_down函数,懒惰标记的下传
void push_down(ll p,ll L,ll R){
ll mid=L+(R-1)>>1;
t[ls(p)].sum=(t[ls(p)].sum*t[p].mu+t[p].add*(mid-L+1))%mod;
t[rs(p)].sum=(t[rs(p)].sum*t[p].mu+t[p].add*(R-mid))%mod;
t[ls(p)].mu=(t[ls(p)].mu*t[p].mu)%mod;
t[rs(p)].mu=(t[rs(p)].mu*t[p].mu)%mod;
t[ls(p)].add=(t[ls(p)].add*t[p].mu+t[p].add)%mod;
t[rs(p)].add=(t[rs(p)].add*t[p].mu+t[p].add)%mod;
t[p].add=0; t[p].mu=1;
return ;
}
7.区间和,这个背过就好,所有的线段树都一样
ll query(ll p,ll L,ll R,ll l,ll r){
ll ans=0;
if(l<=L&&R<=r) return t[p].sum;
ll mid=L+(R-1)>>1;
push_down(p,L,R);
if(l<=mid) ans+=query(ls(p),L,mid,l,r);
if(r>mid) ans+=query(rs(p),mid+1,R,l,r);
return ans;
}
8.根据二叉树的性质可以得到一个检验的树的程序
void print(ll p){
if(t[p].s==0) return ;
printf("%d ",t[p].s);
print(ls(p)),print(rs(p));
printf("
");
}
9.区间替换暂时鸽掉,哪天脑子清晰再来写
后记:感觉线段树2的代码可以水掉线段树1;
code
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
const int N=1e5+10;
ll n,m,mod;
struct tree{
ll add,mu,sum;
}t[N<<2];
ll num[N];
ll ls(ll p){ return p<<1;}
ll rs(ll p){ return p<<1|1;}
ll push_up_sum(ll p){
return t[p].sum= t[ls(p)].sum + t[rs(p)].sum;
}
void push_down(ll p,ll L,ll R){
ll mid=L+(R-1)>>1;
t[ls(p)].sum=(t[ls(p)].sum*t[p].mu+t[p].add*(mid-L+1))%mod;
t[rs(p)].sum=(t[rs(p)].sum*t[p].mu+t[p].add*(R-mid))%mod;
t[ls(p)].mu=(t[ls(p)].mu*t[p].mu)%mod;
t[rs(p)].mu=(t[rs(p)].mu*t[p].mu)%mod;
t[ls(p)].add=(t[ls(p)].add*t[p].mu+t[p].add)%mod;
t[rs(p)].add=(t[rs(p)].add*t[p].mu+t[p].add)%mod;
t[p].add=0; t[p].mu=1;
return ;
}
void mu(ll p,ll L,ll R,ll l,ll r,ll k){
if(l<=L&&R<=r){
t[p].sum=t[p].sum*k%mod;
t[p].mu=t[p].mu*k%mod;
t[p].add=t[p].add*k%mod;
return ;}
push_down(p,L,R);
ll mid=L+(R-1)>>1;
if(l<=mid) mu(ls(p),L,mid,l,r,k);
if(mid<r) mu(rs(p),mid+1,R,l,r,k);
push_up_sum(p);
}
void add(ll p,ll L,ll R,ll l,ll r,ll k){
if(l<=L&&R<=r){
t[p].add = (t[p].add+k);
t[p].sum = t[p].sum + k*(R-L+1);
return;
}
push_down(p,L,R);
ll mid = L+(R-1)>>1;
if(l<=mid) add(ls(p),L,mid,l,r,k);
if(mid<r) add(rs(p),mid+1,R,l,r,k);
push_up_sum(p);
}
void build(ll p,ll l, ll r){
t[p].add=0,t[p].mu=1;
if(l==r){ t[p].sum=num[l];return ; }
ll mid=l+(r-1)>>1;
build(ls(p),l,mid),build(rs(p),mid+1,r);
push_up_sum(p);
}
ll query(ll p,ll L,ll R,ll l,ll r){
ll ans=0;
if(l<=L&&R<=r) return t[p].sum;
ll mid=L+(R-1)>>1;
push_down(p,L,R);
if(l<=mid) ans+=query(ls(p),L,mid,l,r);
if(r>mid) ans+=query(rs(p),mid+1,R,l,r);
return ans;
}
int main(){
scanf("%lld%lld%lld",&n,&m,&mod);
for(int i=1;i<=n;i++) scanf("%lld",&num[i]);
build(1,1,n);
// print();
int tpy;ll x,y,k;
while(m--){
scanf("%d",&tpy);
switch(tpy){
case 1:{
scanf("%lld%lld%lld",&x,&y,&k);
mu(1,1,n,x,y,k);
// puts("");
// print();
break;
}
case 2:{
scanf("%lld%lld%lld",&x,&y,&k);
add(1,1,n,x,y,k);
// puts("");
// print();
break;
}
case 3:{
scanf("%lld%lld",&x,&y);
printf("%lld
",query(1,1,n,x,y)%mod);
break;
}
}
}
}