線段樹 維護序列

2021-10-02 14:38:07 字數 2421 閱讀 6655

老師交給小可可乙個維護數列的任務,現在小可可希望你來幫他完成。

有長為 n 的數列,不妨設為 a1,a2,…,an。

有如下三種操作形式:

把數列中的一段數全部乘乙個值;

把數列中的一段數全部加乙個值;

詢問數列中的一段數的和,由於答案可能很大,你只需輸出這個數模 p 的值。

輸入格式

第一行兩個整數 n 和 p;

第二行含有 n 個非負整數,從左到右依次為 a1,a2,…,an;

第三行有乙個整數 m,表示操作總數;

從第四行開始每行描述乙個操作,輸入的操作有以下三種形式:

操作 1:1 t g c,表示把所有滿足 t≤i≤g 的 ai 改為 ai×c;

操作 2:2 t g c,表示把所有滿足 t≤i≤g 的 ai 改為 ai+c;

操作 3:3 t g,詢問所有滿足 t≤i≤g 的 ai 的和模 p 的值。

同一行相鄰兩數之間用乙個空格隔開,每行開頭和末尾沒有多餘空格。

輸出格式

對每個操作 3,按照它在輸入**現的順序,依次輸出一行乙個整數表示詢問結果。

資料範圍

1 ≤n

,m≤1

05

1≤n,m≤10^5

1≤n,m≤

1051≤t

≤g≤n

1≤t≤g≤n

1≤t≤g≤

n,0 ≤c

,ai≤

10

90≤c,a_i≤10^9

0≤c,ai

​≤10

9,1 ≤p

≤109

1≤p≤10^9

1≤p≤10

9輸入樣例:

7 43

1 2 3 4 5 6 7

51 2 5 5

3 2 4

2 3 7 9

3 1 3

3 4 7

輸出樣例:235

8樣例解釋

初始時數列為 ;

經過第 1 次操作後,數列為 ;

對第 2 次操作,和為 10+15+20=45,模 43 的結果是 2;

經過第 3 次操作後,數列為 ;

對第 4 次操作,和為 1+10+24=35,模 43 的結果是 35;

對第 5 次操作,和為 29+34+15+16=94,模 43 的結果是 8。

我們發現我們先加再乘的方法並不好辦。於是寫一下表示式用多項式來進行表示發現如果用先乘再加的方法就好處理很多了。

#include

#define int long long

using

namespace std;

#define lson u<<1

#define rson u<<1|1

const

int n=

1e5+7;

int n,m,p;

int a[n]

;struct node

tr[n<<2]

;void

pushup

(node &u,node &l,node &r)

void

pushup

(int u)

void

build

(int u,

int l,

int r)

;return;}

int mid=l+r>>1;

tr[u]=;

build

(lson,l,mid)

;build

(rson,mid+

1,r)

;pushup

(u);

}void

evu(node &u,

int add,

int mul)

void

pushdown

(int u)

void

modify

(int u,

int l,

int r,

int add,

int mul)

pushdown

(u);

int mid=tr[u]

.l+tr[u]

.r>>1;

if(l<=mid)

modify

(lson,l,r,add,mul);if

(r>mid)

modify

(rson,l,r,add,mul)

;pushup

(u);

}node query

(int u,

int l,

int r)

}signed

main()

else

if(t==2)

else

}}

線段樹 I 維護序列

老師交給小可可乙個維護數列的任務,現在小可可希望你來幫他完成。有長為 nn 的數列,不妨設為 a1,a2,ana1,a2,an。有如下三種操作形式 input 第一行兩個整數 nn 和 pp 第二行含有 nn 個非負整數,從左到右依次為 a1,a2,ana1,a2,an 第三行有乙個整數 mm,表示...

線段樹yy(線段樹維護括號序列 LCA)

沒有題目鏈結 一顆有 n 個節點的樹,q 組詢問,支援兩種操作 1.單點修改 2.路徑求和。1 n,q 1e5 題解 那麼可以建立一顆有根樹,每次更新時為兩個單點更新 加一次減一次 每次查詢時則是查詢 根的左括號到 x 點的左括號之和 根的左括號到 y 點的左括號之和 2 根的左括號到 x 與 y ...

模板 維護序列2(線段樹)

取模取掛可真是令人質壁分離。兩兩乘積和可以直接用兩個區間的區間和相乘再加上兩個區間各自的乘積和得到,而相鄰乘積和直接兩段相加再加上左區間右端點與右區間左端點乘積就好了。注意 mod mod includeusing namespace std typedef long long ll const l...