P3373 模板 線段樹2

2021-09-25 11:32:36 字數 2168 閱讀 9328

如題,已知乙個數列,你需要進行下面三種操作:

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項的初始值。接下來...