已知乙個數列,你需要進行下面三種操作:
將某區間每乙個數乘上 xx
將某區間每乙個數加上 xx
求出某區間每乙個數的和
第一行包含三個整數 n,m,pn,m,p,分別表示該數列數字的個數、操作的總個數和模數。
第二行包含 nn 個用空格分隔的整數,其中第 ii 個數字表示數列第 ii 項的初始值。
接下來 mm 行每行包含若干個整數,表示乙個操作,具體如下:
操作 1: 格式:1 x y k 含義:將區間 [x,y][x,y] 內每個數乘上 kk
操作 2: 格式:2 x y k 含義:將區間 [x,y][x,y] 內每個數加上 kk
操作 3: 格式:3 x y 含義:輸出區間 [x,y][x,y] 內每個數的和對 pp 取模所得的結果
輸出包含若干行整數,即為所有操作 33 的結果
5 5 38
1 5 4 2 3
2 1 4 1
3 2 5
1 2 4 2
2 3 5 5
3 1 4172
這是一道線段樹的模板題,主要考察對 laze_tag 的應用,因為這裡涉及到乘法和加法,所以需要兩個懶標記。
struct
tree[n <<2]
;
所以顯然易見的,我們可以寫出下面的 pushup 和 pushdown **來。注意:這裡需要區分加法和乘法的運算順序。 因為建樹**幾乎所有線段樹題都是一樣的,我這裡暫時不給出,唯一需要注意的一點就是在建樹的時候我們需要把乘法懶標記初始化為 1 。
void
update
(int node,
int laze1,
int laze2)
void
pushdown
(int node)
void
pushup
(int node)
常規思路,我們需要寫兩個 change 函式來分別針對加法和乘法進行修改,太懶,不想敲這個** ,那麼我們能不能把加法和乘法合併為乙個表示式呢,其實是可以的。例:對乙個數 x ,我們有這樣乙個式子 x * a + b,如果讓 x 加 k,則使 a = 1, b = k 即可,如果讓 x 乘以 k,則讓 a = k, b = 0 即可。這樣操作的話,我們的 change 函式也就只需要寫乙個了。**如下:
void
change
(int node,
int l,
int r,
int k,
int type)
//type為1代表乘,為2代表加
if(tree[node]
.laze1 !=
1|| tree[node]
.laze2 !=0)
pushdown
(node)
;int mid =
(tree[node]
.l + tree[node]
.r)>>1;
if(r <= mid)
change
(node <<
1, l, r, k, type)
;else
if(l > mid)
change
(node <<1|
1, l, r, k, type)
;else
pushup
(node)
;}
最後,附上這一題的完整**
#include
#include
using
namespace std;
typedef
long
long ll;
const
int n =
1e5+5;
ll arr[n]
;int p;
struct
tree[n <<2]
;//建樹
void
build
(int node,
int l,
int r)
else
}//更新當前節點資訊
void
update
(int node,
int laze1,
int laze2)
//下放懶標記,即更新左子節點和右子節點
void
pushdown
(int node)
//更新當前節點
void
pushup
(int node)
//對區間進行修改
void
change
(int node,
int l,
int r,
int k,
int type)
//type為1代表乘,為2代表加
if(tree[node]
.laze1 !=
1|| tree[node]
.laze2 !=0)
pushdown
(node)
;int mid =
(tree[node]
.l + tree[node]
.r)>>1;
if(r <= mid)
change
(node <<
1, l, r, k, type)
;else
if(l > mid)
change
(node <<1|
1, l, r, k, type)
;else
pushup
(node);}
//查詢區間 l 到 r
ll query
(int node,
int l,
int r)
intmain()
else
}return0;
}
加法乘法線段樹模板
p2023 ahoi2009 維護序列 指定乙個區間 加上或者乘以 v,查詢乙個區間所有元素和 p 與純加法線段樹不同的是,lazy tag 的傳遞 x y v xv yv。所以每次乘法,都要把加法的lazy tag v 而加法與加法線段樹的操作一樣 include include typedef ...
線段樹的區間加法與區間乘法
題目描述 如題,已知乙個數列,你需要進行下面兩種操作 將某區間每乙個數加上 kk。求出某區間每乙個數的和。輸入格式 第一行包含兩個整數 n,mn,m,分別表示該數列數字的個數和操作的總個數。第二行包含 nn 個用空格分隔的整數,其中第 ii 個數字表示數列第 ii 項的初始值。接下來 mm 行每行包...
洛谷P3373 線段樹2 乘法加法模板線段樹
這個模板題可真是有點意思。重點在lazytag上,加上乘法操作的tag。update乘的時候要把加的標記也乘一下!下放標記的時候也要記得先乘後加!include include define maxn 1000001 define ll long long using namespace std u...