如題,已知乙個數列,你需要進行下面三種操作:
1.將某區間每乙個數乘上x
2.將某區間每乙個數加上x
3.求出某區間每乙個數的和
#include
#include
using
namespace std;
const
int maxn=
100005
;int n,m,p;
long
long arr[maxn]
;struct tree
nd[4
*maxn]
;void
scanff()
void
build_tree
(int rt,
int l,
int r)
int mid=
(r+l)
>>1;
build_tree(2
*rt,l,mid)
;build_tree(2
*rt+
1,mid+
1,r)
; nd[rt]
.val=
(nd[
2*rt]
.val+nd[
2*rt+1]
.val)
%p;}
/*此題的重難點。
首先考慮懶標記下傳時,兒子節點的值該如何更改:顯然是兒子節點值乘以乘法標記值,
再加上兒子區間長度乘以加法標記值。
再考慮標記合併。乘法標記下傳時,兒子節點的乘法標記、加法標記都乘以父親節點的乘法標記,
兒子節點的加法標記還要加上父親節點的加法標記。
最後不要忘了清空父親節點的懶標記。
*/void
spread
(int rt,
int l,
int r)
/*此題的另乙個易錯點:
考慮乙個區間先加a再乘b,val=(val+a)*b=val*b+a*b;
先乘b再加a,val=val*b+a。
因此給區間放乘法標記的時候,加法標記也要乘以此乘法標記。
*/void
update_mul
(int rt,
int l,
int r,
int c_l,
int c_r,
int mul)
spread
(rt,l,r)
;int mid=
(r+l)
>>1;
update_mul(2
*rt,l,mid,c_l,c_r,mul)
;update_mul(2
*rt+
1,mid+
1,r,c_l,c_r,mul)
; nd[rt]
.val=
(nd[
2*rt]
.val+nd[
2*rt+1]
.val)
%p;return;}
//區間新增加法標記時不需要管乘法標記
void
update_add
(int rt,
int l,
int r,
int c_l,
int c_r,
int ad)
spread
(rt,l,r)
;int mid=
(r+l)
>>1;
update_add(2
*rt,l,mid,c_l,c_r,ad)
;update_add(2
*rt+
1,mid+
1,r,c_l,c_r,ad)
; nd[rt]
.val=
(nd[
2*rt]
.val+nd[
2*rt+1]
.val)
%p;return;}
long
long
ask(
int rt,
int l,
int r,
int a_l,
int a_r)
void
work()
if(a==2)
if(a==3)
}}intmain()
P3373 模板 線段樹 2
ac 這裡的延遲標記要開兩個,分別記錄加法的值和乘法的值,但是乘法和加法的優先順序不一樣,不規定他們的順序的話會有錯誤,所以可以規定乘法優先,即規定好該結點的值等於該節點的值 父節點的乘法延遲標記的值 父節點加法延遲標記的值 區間長度,即,sum num 2 sum num 2 add num wc...
P3373 模板 線段樹 2
題目描述 如題,已知乙個數列,你需要進行下面三種操作 1.將某區間每乙個數乘上x 2.將某區間每乙個數加上x 3.求出某區間每乙個數的和 輸入格式 第一行包含三個整數n m p,分別表示該數列數字的個數 操作的總個數和模數。第二行包含n個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。接下來...
P3373 模板 線段樹 2
題目描述 如題,已知乙個數列,你需要進行下面三種操作 1.將某區間每乙個數乘上x 2.將某區間每乙個數加上x 3.求出某區間每乙個數的和 輸入格式 第一行包含三個整數n m p,分別表示該數列數字的個數 操作的總個數和模數。第二行包含n個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。接下來...