【模板】线段树
1.只维护加法
#include<cstdio>
using namespace std;
typedef long long ll;
const int NN = 1e5+8;
int n,m;
ll a[NN];
struct seg{
ll l,r;
ll sum,add;
#define l(x) tree[x].l
#define r(x) tree[x].r
#define sum(x) tree[x].sum
#define add(x) tree[x].add
#define ls(x) x << 1
#define rs(x) x << 1 | 1
}tree[NN<<2];
void addlz(ll x,ll d){
add(x) += d;sum(x) += d*(r(x)-l(x)+1);
}
void pushdown(int x){
addlz(ls(x),add(x));addlz(rs(x),add(x));
add(x) = 0;
return;
}
void pushup(int x){
sum(x) = sum(ls(x)) + sum(rs(x));
}
void build(int p,int l,int r){
l(p) = l;r(p) = r;
if(l == r){sum(p) = a[l];return;}
int mid = (l+r)>>1;
build(ls(p),l,mid);
build(rs(p),mid+1,r);
pushup(p);
}
void change(ll p,ll l,ll r,ll d){
if(l <= l(p) && r(p) <= r){addlz(p,d);return;}
pushdown(p);
ll mid = (l(p)+r(p))>>1;
if(l <= mid) change(ls(p),l,r,d);
if(r > mid) change(rs(p),l,r,d);
pushup(p);
}
ll query(int p,int l,int r){
if(l <= l(p) && r(p) <= r){return sum(p);}
ll mid = (l(p)+r(p))>>1;
pushdown(p);
ll res = 0;
if(l <= mid) res += query(ls(p),l,r);
if(r > mid) res += query(rs(p),l,r);
return res;
}
int main(){
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)
scanf("%lld",&a[i]);
build(1,1,m);
for(int i = 1,type,a,b,c; i <= m; i++){
scanf("%d",&type);
if(type == 1){
scanf("%d%d%d",&a,&b,&c);
change(1,a,b,c);
}
if(type == 2){
scanf("%d%d",&a,&b);
printf("%lld\n",query(1,a,b));
}
// print(1);
}
}
2. 维护加法和乘法
#include<cstdio>
using namespace std;
typedef long long ll;
const int NN = 1e5+8;
int n,m,mod;
ll a[NN];
inline ll Calc(const ll a,const ll b){ll res = a+b;return res-(res>=mod?mod:0);}//加法取模封装
inline ll Mult(const ll a, const ll b){return a*b%mod;}//乘法取模封装
struct seg{
ll l,r;//记录区间左右端点
ll sum,add,mul;//sum为区间和,add为加法标记,mul为乘法标记
#define l(x) tree[x].l
#define r(x) tree[x].r
#define sum(x) tree[x].sum
#define add(x) tree[x].add
#define mul(x) tree[x].mul
#define ls(x) x << 1
#define rs(x) x << 1 | 1
}tree[NN<<2];
void addlz(ll x,ll d){
add(x) = Calc(add(x),d);sum(x) = Calc(sum(x),Mult(d,r(x)-l(x)+1));
}//对节点进行加法操作
void mullz(ll x,ll d){
mul(x) = Mult(mul(x),d);sum(x) = Mult(sum(x),d);add(x) = Mult(add(x),d);
}//对节点进行乘法操作
void pushdown(int x){
mullz(ls(x),mul(x));mullz(rs(x),mul(x));
addlz(ls(x),add(x));addlz(rs(x),add(x));
add(x) = 0; mul(x) = 1;
return;
}//下传标记
void pushup(int x){
sum(x) = Calc(sum(ls(x)) , sum(rs(x)));
}//上传结果
void build(int p,int l,int r){
mul(p) = 1;
l(p) = l;r(p) = r;
if(l == r){sum(p) = a[l];return;}
int mid = (l+r)>>1;
build(ls(p),l,mid);
build(rs(p),mid+1,r);
pushup(p);
}//建树
void change_add(ll p,ll l,ll r,ll d){
if(l <= l(p) && r(p) <= r){addlz(p,d);return;}
pushdown(p);
ll mid = (l(p)+r(p))>>1;
if(l <= mid) change_add(ls(p),l,r,d);
if(r > mid) change_add(rs(p),l,r,d);
pushup(p);
}//区间加(l == r 时为单点加)
void change_mul(ll p,ll l,ll r,ll d){
if(l <= l(p) && r(p) <= r){mullz(p,d);return;}
pushdown(p);
ll mid = (l(p)+r(p))>>1;
if(l <= mid) change_mul(ls(p),l,r,d);
if(r > mid) change_mul(rs(p),l,r,d);
pushup(p);
}//区间乘(l == r时为单点乘)
ll query(int p,int l,int r){
if(l <= l(p) && r(p) <= r){return sum(p);}
ll mid = (l(p)+r(p))>>1;
pushdown(p);
ll res = 0;
if(l <= mid) res = Calc(res,query(ls(p),l,r));
if(r > mid) res = Calc(res,query(rs(p),l,r));
return res;
} //区间查询
//void print(ll p){
// printf("%lld [%lld,%lld] sum:%lld add:%lld mul:%lld\n",p,l(p),r(p),sum(p),add(p),mul(p));
// if(l(p) == r(p))return;
// print(ls(p));
// print(rs(p));
//} 此为调试语句
int main(){
scanf("%d%d%d",&n,&m,&mod);
for(int i = 1; i <= n; i++)
scanf("%lld",&a[i]);
build(1,1,m);
// print(1);
for(int i = 1,type,a,b,c; i <= m; i++){
scanf("%d",&type);
if(type == 1){
scanf("%d%d%d",&a,&b,&c);
change_mul(1,a,b,c);
}
else if(type == 2){
scanf("%d%d%d",&a,&b,&c);
change_add(1,a,b,c);
}
else if(type == 3){
scanf("%d%d",&a,&b);
printf("%lld\n",query(1,a,b));
}
// print(1);
}
}
本文来自博客园,作者:ricky_lin,转载请注明原文链接:https://www.cnblogs.com/rickylin/p/17049908.html