線段樹 AHOI 2009 維護序列

2021-09-19 05:24:36 字數 2632 閱讀 9568

老師交給小可可乙個維護數列的任務,現在小可可希望你來幫他完成。 有長為n的數列,不妨設為a1,a2,…,an 。有如下三種操作形式:

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

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

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

第一行兩個整數n和p(1≤p≤1000000000)。

第二行含有n個非負整數,從左到右依次為a1,a2,…,an, (0≤ai≤1000000000,1≤i≤n)。

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

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

操作1:「1 t g c」(不含雙引號)。表示把所有滿足t≤i≤g的ai改為ai×c(1≤t≤g≤n,0≤c≤1000000000)。

操作2:「2 t g c」(不含雙引號)。表示把所有滿足t≤i≤g的ai改為ai+c (1≤t≤g≤n,0≤c≤1000000000)。

操作3:「3 t g」(不含雙引號)。詢問所有滿足t≤i≤g的ai的和模p的值 (1≤t≤g≤n)。

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

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

輸入樣例#1:

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

輸出樣例#1:

2

358

初始時數列為(1,2,3,4,5,6,7)。

經過第1次操作後,數列為(1,10,15,20,25,6,7)。

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

經過第3次操作後,數列為(1,10,24,29,34,15,16}

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

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

【題解】:

這個題目就是乙個模板題。但是萬事開頭難,自己也錯了不少次才ac的。

這個題目每乙個節點不是以前的單純記錄add[ ]即可。

還多了乙個乘法的操作:

因為多了乙個乘法的操作,所以必須增加乙個mul[ ] 與之對應才行。

後來遇到問題了,又有乘法又有加法怎麼弄呢????

這個問題真的弄得頭都大了。

後來瞄了一眼題解才知道,原來只要一直滿足先乘法後加法才可以弄。

如果當前位置有乘法,想轉移到子節點,

那麼pushdown操作必須先乘後加。

首先當前節點 mul = k,add = c

k(ax+b)=ak x + bk

然後 ak *x + b*k+c

如果到了葉子節點那麼就是直接把對應的位置算出即可。

#include using namespace std;

typedef long long ll;

const int n = 1e5 + 100;

int n, m, l, r, ins;

ll tree[n << 2], mul[n << 2], add[n << 2], a[n];

ll mod, c, tmp;

void build(int no, int l, int r)

build(no << 1, l, mid);

build(no << 1 | 1, mid + 1, r);

tree[no] = (tree[no << 1] + tree[no << 1 | 1]) % mod;

}void mul(int no, int l, int r, ll k)

void add(int no, int l, int r, ll k)

void push_down(int no, int l, int r)

void modify(int no, int l, int r, int x, int y, ll k, int f)

if (x <= l && r <= y && f == 2)

int mid = (l + r) >> 1;

push_down(no, l, r);

if (x <= mid)

modify(no << 1, l, mid, x, y, k, f);

if (mid < y)

modify(no << 1 | 1, mid + 1, r, x, y, k, f);

tree[no] = (tree[no << 1] + tree[no << 1 | 1]) % mod;

}ll query(int no, int l, int r, int x, int y)

void check(int no, int l, int r)

check(no << 1, l, mid);

check(no << 1 | 1, mid + 1, r);

}int main()

build(1, 1, n);

scanf("%d", &m);

while (m--)

}return 0;

}

AHOI2009 維護序列 線段樹

老師交給小可可乙個維護數列的任務,現在小可可希望你來幫他完成。有長為n的數列,不妨設為a1,a2,an 有如下三種操作形式 1 把數列中的一段數全部乘乙個值 2 把數列中的一段數全部加乙個值 3 詢問數列中的一段數的和,由於答案可能很大,你只需輸出這個數模p的值。線段樹,打個乘法lazy標記即可 i...

AHOI2009 維護序列

題目描述 有乙個長為 n n leq 10 5 的序列,支援三種操作,分別是給一段區間 l,r 內的所有數加上 乘上乙個數,以及求一段區間 l,r 中的數字的和。輸入樣例 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 輸出樣例 2 358...

bzoj1798 ahoi2009 維護序列

time limit 30 sec memory limit 64 mb submit 3714 solved 1364 submit status discuss 老師交給小可可乙個維護數列的任務,現在小可可希望你來幫他完成。有長為n的數列,不妨設為a1,a2,an 有如下三種操作形式 1 把數列...