生活随笔
收集整理的這篇文章主要介紹了
                                
P3373 【模板】线段树 2(区间乘法+区间加法+区间求和)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
 
                                
                            
                            
                            題目描述
 如題,已知一個數列,你需要進行下面三種操作:
 
將某區間每一個數乘上 xx
 
將某區間每一個數加上 xx
 
求出某區間每一個數的和
 
輸入格式
 第一行包含三個整數 n,m,pn,m,p,分別表示該數列數字的個數、操作的總個數和模數。
 
第二行包含 nn 個用空格分隔的整數,其中第 ii 個數字表示數列第 ii 項的初始值。
 
接下來 mm 行每行包含若干個整數,表示一個操作,具體如下:
 
操作 11: 格式:1 x y k 含義:將區間 [x,y][x,y] 內每個數乘上 kk
 
操作 22: 格式:2 x y k 含義:將區間 [x,y][x,y] 內每個數加上 kk
 
操作 33: 格式:3 x y 含義:輸出區間 [x,y][x,y] 內每個數的和對 pp 取模所得的結果
 
輸出格式
 輸出包含若干行整數,即為所有操作 33 的結果。
 思路:雖然多了一個區間乘法,但是還是蠻難做的。今天才發現我一開始學線段樹的時候做過這道題目,但是在后面的比賽訓練種,并沒有接觸過區間乘法的題目,就給忘的一干二凈,寫篇博客記錄一下。
 需要額外注意的地方:
 ①在pushdown的過程中,我們在計算左右子樹和的時候,采用乘法優先的原則,即規定好segtree[root* 2].value=(segtree[root* 2].value* segtree[root].mul+segtree[root].add*(本區間長度))%p。而不是加法優先的原則。
 ②在對區間進行加一個數的時候,沒有額外需要注意的;但是當區間乘以一個數的時候,這個區間之前加的值,也需要額外的乘以這個數字。
 具體解釋看代碼:
 這個代碼完全可以當作模板了^ _ ^
 
#include<bits/stdc++.h>
#define ll long long
using namespace std
;const int maxx
=1e5+100;
struct node
{int l
,r
;ll sum
,lazyx
,lazyj
;
}p
[maxx
<<2];
int n
,m
,q
;
ll a
[maxx
];inline void pushup(int cur
)
{p
[cur
].sum
=(p
[cur
<<1].sum
+p
[cur
<<1|1].sum
)%q
; 
}
inline void pushdown(int cur
)
{p
[cur
<<1].sum
=(p
[cur
<<1].sum
*p
[cur
].lazyx
+(ll
)(p
[cur
<<1].r
-p
[cur
<<1].l
+1)*p
[cur
].lazyj
)%q
;p
[cur
<<1|1].sum
=(p
[cur
<<1|1].sum
*p
[cur
].lazyx
+(ll
)(p
[cur
<<1|1].r
-p
[cur
<<1|1].l
+1)*p
[cur
].lazyj
)%q
;p
[cur
<<1].lazyj
=(p
[cur
<<1].lazyj
*p
[cur
].lazyx
+p
[cur
].lazyj
)%q
;p
[cur
<<1|1].lazyj
=(p
[cur
<<1|1].lazyj
*p
[cur
].lazyx
+p
[cur
].lazyj
)%q
;p
[cur
<<1].lazyx
=(p
[cur
<<1].lazyx
*p
[cur
].lazyx
)%q
;p
[cur
<<1|1].lazyx
=(p
[cur
<<1|1].lazyx
*p
[cur
].lazyx
)%q
;p
[cur
].lazyj
=0;p
[cur
].lazyx
=1;
}
inline void build(int l
,int r
,int cur
)
{p
[cur
].l
=l
;p
[cur
].r
=r
;p
[cur
].lazyj
=0;p
[cur
].lazyx
=1;if(l
==r
){p
[cur
].sum
=(a
[l
])%q
;return ;}int mid
=l
+r
>>1;build(l
,mid
,cur
<<1);build(mid
+1,r
,cur
<<1|1);pushup(cur
);
}
inline void updatej(int l
,int r
,int cur
,ll x
)
{int L
=p
[cur
].l
;int R
=p
[cur
].r
;if(l
<=L
&&R
<=r
){p
[cur
].lazyj
+=x
;p
[cur
].lazyj
%=q
;p
[cur
].sum
+=(ll
)(p
[cur
].r
-p
[cur
].l
+1)*x
;p
[cur
].sum
%=q
;return ;}pushdown(cur
);int mid
=L
+R
>>1;if(r
<=mid
) updatej(l
,r
,cur
<<1,x
);else if(l
>mid
) updatej(l
,r
,cur
<<1|1,x
);else updatej(l
,mid
,cur
<<1,x
),updatej(mid
+1,r
,cur
<<1|1,x
);pushup(cur
); 
}
inline void updatex(int l
,int r
,int cur
,ll x
)
{int L
=p
[cur
].l
;int R
=p
[cur
].r
;if(l
<=L
&&R
<=r
){p
[cur
].sum
=(p
[cur
].sum
*x
)%q
;p
[cur
].lazyx
=(p
[cur
].lazyx
*x
)%q
;p
[cur
].lazyj
=(p
[cur
].lazyj
*x
)%q
;return ;}pushdown(cur
);int mid
=L
+R
>>1;if(r
<=mid
) updatex(l
,r
,cur
<<1,x
);else if(l
>mid
) updatex(l
,r
,cur
<<1|1,x
);else updatex(l
,mid
,cur
<<1,x
),updatex(mid
+1,r
,cur
<<1|1,x
);pushup(cur
);
}
inline ll 
query(int l
,int r
,int cur
)
{int L
=p
[cur
].l
;int R
=p
[cur
].r
;if(l
<=L
&&R
<=r
) return p
[cur
].sum
%q
;pushdown(cur
);int mid
=L
+R
>>1;if(r
<=mid
) return query(l
,r
,cur
<<1)%q
;else if(l
>mid
) return query(l
,r
,cur
<<1|1)%q
;else return (query(l
,mid
,cur
<<1)%q
+query(mid
+1,r
,cur
<<1|1)%q
)%q
;
}
int main()
{while(~scanf("%d%d%d",&n
,&m
,&q
)){for(int i
=1;i
<=n
;i
++) scanf("%lld",&a
[i
]);build(1,n
,1);int x
,y
,z
;ll k
;while(m
--){scanf("%d",&x
);if(x
==1){scanf("%d%d%lld",&y
,&z
,&k
);updatex(y
,z
,1,k
);}else if(x
==2){scanf("%d%d%lld",&y
,&z
,&k
);updatej(y
,z
,1,k
);}else{scanf("%d%d",&y
,&z
);printf("%lld\n",query(y
,z
,1)%q
);} }}return 0;
}
 
努力加油a啊
                            總結
                            
                                以上是生活随笔為你收集整理的P3373 【模板】线段树 2(区间乘法+区间加法+区间求和)的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                            
                                如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。