突然发现以前很多模板题没打,就过来补一补
线段树2
线
段
树
2
主
要
基
于
这
样
一
个
思
想
—
—
即
乘
法
运
算
可
以
将
t
a
g
和
t
r
e
e
值
同
时
乘
,
然
后
像
线
段
树
1
一
样
打
就
行
了
线段树2主要基于这样一个思想——即乘法运算可以将tag和tree值同时乘,然后像线段树1一样打就行了
线段树2主要基于这样一个思想——即乘法运算可以将tag和tree值同时乘,然后像线段树1一样打就行了
即tag1[i]为乘法打的tag,tag2[i]为加法打的tag
由
于
我
没
写
过
线
段
树
1
的
博
客
,
所
以
在
这
里
简
单
讲
一
讲
由于我没写过线段树1的博客,所以在这里简单讲一讲
由于我没写过线段树1的博客,所以在这里简单讲一讲
首
先
,
类
似
于
二
分
,
建
一
颗
树
(
对
于
本
题
来
说
,
还
需
要
将
t
a
g
1
赋
值
为
1
)
首先,类似于二分,建一颗树(对于本题来说,还需要将tag1赋值为1)
首先,类似于二分,建一颗树(对于本题来说,还需要将tag1赋值为1)
void make_tree(ll l,ll r,ll p){
if(l==r){
tag1[p]=1;tree[p]=a[l]%mod;
return;
}
ll mid=(l+r)>>1;
make_tree(l,mid,p<<1);
make_tree(mid+1,r,p<<1|1);
push_up(p);tag1[p]=1;
}
一 段 区 间 ( 记 这 段 区 间 为 [ f s , s e ] ) 加 就 在 树 上 找 树 上 找 可 以 被 [ f s , s e ] 覆 盖 的 点 , 先 将 t r e e 值 中 的 每 个 数 加 上 v a l ( 更 新 的 值 ) , 即 t r e e + = v a l ∗ ( r − l + 1 ) , 然 后 再 把 t a g 2 的 值 加 v a l 就 行 了 ( p u s h d o w n 后 面 再 具 体 解 释 ) 一段区间(记这段区间为[fs,se])加就在树上找树上找可以被[fs,se]覆盖的点,先将tree值中的每个数加上val(更新的值),即tree+=val*(r-l+1),然后再把tag2的值加val就行了(pushdown后面再具体解释) 一段区间(记这段区间为[fs,se])加就在树上找树上找可以被[fs,se]覆盖的点,先将tree值中的每个数加上val(更新的值),即tree+=val∗(r−l+1),然后再把tag2的值加val就行了(pushdown后面再具体解释)
void uppdate1(ll l,ll r,ll p,ll fs,ll se,ll val){
if(fs<=l&&r<=se){
tree[p]=(1ll*tree[p]*(val))%mod;
tag1[p]=1ll*(tag1[p]*val)%mod;tag2[p]=1ll*(tag2[p]*val)%mod;
return;
}
if((tag1[p]!=1)||(tag2[p]!=0)) pushdown(l,r,p);
ll mid=(l+r)>>1;
if(fs<=mid) uppdate1(l,mid,p<<1,fs,se,val);
if(se>mid) uppdate1(mid+1,r,p<<1|1,fs,se,val);
push_up(p);
}
一 段 区 间 ( 记 这 段 区 间 为 [ f s , s e ] ) 乘 , 就 把 可 以 覆 盖 到 的 树 上 的 点 的 t r e e 值 乘 上 v a l ( 乘 法 改 变 的 值 ) , 同 时 将 t a g 2 和 t a g 1 乘 上 v a l , 因 为 t r e e [ i ] 的 子 树 中 的 任 意 点 j 的 实 际 值 都 是 t r e e [ j ] ∗ t a g 1 [ j ] + t a g 2 [ j ] ∗ ( r j − l j + 1 ) , 即 a ∗ ( b + c ) = a ∗ ( b ) + a ∗ ( c ) , 所 以 我 们 直 接 将 需 要 加 的 值 和 原 值 乘 上 v a l 即 可 一段区间(记这段区间为[fs,se])乘,就把可以覆盖到的树上的点的tree值乘上val(乘法改变的值),同时将tag2和tag1乘上val,因为tree[i]的子树中的任意点j的实际值都是tree[j]*tag1[j]+tag2[j]*(r_j-l_j+1),即a*(b+c)=a*(b)+a*(c),所以我们直接将需要加的值和原值乘上val即可 一段区间(记这段区间为[fs,se])乘,就把可以覆盖到的树上的点的tree值乘上val(乘法改变的值),同时将tag2和tag1乘上val,因为tree[i]的子树中的任意点j的实际值都是tree[j]∗tag1[j]+tag2[j]∗(rj−lj+1),即a∗(b+c)=a∗(b)+a∗(c),所以我们直接将需要加的值和原值乘上val即可
void uppdate2(ll l,ll r,ll p,ll fs,ll se,ll val){
if(fs<=l&&r<=se){
tree[p]=(((r-l+1)%mod)*val%mod+tree[p]%mod)%mod;
tag2[p]=1ll*(tag2[p]%mod+val)%mod;
return;
}
if((tag1[p]!=1)||(tag2[p]!=0)) pushdown(l,r,p);
ll mid=(l+r)>>1;
if(fs<=mid) uppdate2(l,mid,p<<1,fs,se,val);
if(se>mid) uppdate2(mid+1,r,p<<1|1,fs,se,val);
push_up(p);
}
因为要加的值已经乘过了,所以pushdown时先乘再加(这里一个小错误我调了很久)
void pushdown(ll l,ll r,ll p){
ll mid=((l+r)>>1);
tag1[p<<1]=1ll*(tag1[p<<1]*tag1[p])%mod;tag2[p<<1]=(tag2[p<<1]*tag1[p]+tag2[p])%mod;
tag1[p<<1|1]=1ll*(tag1[p<<1|1]*tag1[p])%mod;tag2[p<<1|1]=1ll*(tag2[p<<1|1]*tag1[p]+tag2[p])%mod;
tree[p<<1]=(1ll*tree[p<<1]*tag1[p]%mod+(tag2[p]*((mid-l+1)%mod)%mod))%mod;/*区间中的每个数都要加tag[2]*/
tree[p<<1|1]=(1ll*tree[p<<1|1]*tag1[p]%mod+(tag2[p]*((r-mid)%mod)%mod))%mod;/*区间中的每个数都要加tag[2]*/
tag1[p]=1,tag2[p]=0;
}
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1e5+5;
ll n,m,mod;
ll tree[N*4],tag1[N*4],tag2[N*4],a[N];
void push_up(ll p){
tree[p]=(tree[p<<1]+tree[p<<1|1])%mod;
}
void make_tree(ll l,ll r,ll p){
if(l==r){
tag1[p]=1;tree[p]=a[l]%mod;
return;
}
ll mid=(l+r)>>1;
make_tree(l,mid,p<<1);
make_tree(mid+1,r,p<<1|1);
push_up(p);tag1[p]=1;
}
void pushdown(ll l,ll r,ll p){
ll mid=((l+r)>>1);
tag1[p<<1]=1ll*(tag1[p<<1]*tag1[p])%mod;tag2[p<<1]=(tag2[p<<1]*tag1[p]+tag2[p])%mod;
tag1[p<<1|1]=1ll*(tag1[p<<1|1]*tag1[p])%mod;tag2[p<<1|1]=1ll*(tag2[p<<1|1]*tag1[p]+tag2[p])%mod;
tree[p<<1]=(1ll*tree[p<<1]*tag1[p]%mod+(tag2[p]*((mid-l+1)%mod)%mod))%mod;/*区间中的每个数都要加tag[2]*/
tree[p<<1|1]=(1ll*tree[p<<1|1]*tag1[p]%mod+(tag2[p]*((r-mid)%mod)%mod))%mod;/*区间中的每个数都要加tag[2]*/
tag1[p]=1,tag2[p]=0;
}
void uppdate1(ll l,ll r,ll p,ll fs,ll se,ll val){
if(fs<=l&&r<=se){
tree[p]=(1ll*tree[p]*(val))%mod;
tag1[p]=1ll*(tag1[p]*val)%mod;tag2[p]=1ll*(tag2[p]*val)%mod;
return;
}
if((tag1[p]!=1)||(tag2[p]!=0)) pushdown(l,r,p);
ll mid=(l+r)>>1;
if(fs<=mid) uppdate1(l,mid,p<<1,fs,se,val);
if(se>mid) uppdate1(mid+1,r,p<<1|1,fs,se,val);
push_up(p);
}
void uppdate2(ll l,ll r,ll p,ll fs,ll se,ll val){
if(fs<=l&&r<=se){
tree[p]=(((r-l+1)%mod)*val%mod+tree[p]%mod)%mod;
tag2[p]=1ll*(tag2[p]%mod+val)%mod;
return;
}
if((tag1[p]!=1)||(tag2[p]!=0)) pushdown(l,r,p);
ll mid=(l+r)>>1;
if(fs<=mid) uppdate2(l,mid,p<<1,fs,se,val);
if(se>mid) uppdate2(mid+1,r,p<<1|1,fs,se,val);
push_up(p);
}
ll ans=0;
void query(ll l,ll r,ll p,ll fs,ll se){
if(fs<=l&&r<=se){
ans=(ans+tree[p])%mod;
return;
}
if(tag1[p]!=1||tag2[p]!=0) pushdown(l,r,p);
ll mid=(l+r)>>1;
if(fs<=mid) query(l,mid,p<<1,fs,se);
if(se>mid) query(mid+1,r,p<<1|1,fs,se);
push_up(p);
}
int main(){
scanf("%lld%lld%lld",&n,&m,&mod);
for(ll i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
make_tree(1,n,1);
for(ll i=1;i<=m;i++){
ll tp;
scanf("%lld",&tp);
if(tp==1){
ll x,y;
ll k;
scanf("%lld%lld%lld",&x,&y,&k);k%=mod;
uppdate1(1,n,1,x,y,k);
}
if(tp==2){
ll x,y;
ll k;
scanf("%lld%lld%lld",&x,&y,&k);k%=mod;
uppdate2(1,n,1,x,y,k);
}
if(tp==3){
ll x,y;
ans=0;
scanf("%lld%lld",&x,&y);
query(1,n,1,x,y);
printf("%lld\n",ans);
}
}
}