BZOJ1798: [Ahoi2009]Seq 维护序列seq
Description
老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 有长为N的数列,不妨设为a1,a2,…,aN 。有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值。
Input
第一行两个整数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)。 同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。
Output
对每个操作3,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。
Sample Input
7 43
1 2 3 4 5 6 7
5
1 2 5 5
3 2 4
2 3 7 9
3 1 3
3 4 7
1 2 3 4 5 6 7
5
1 2 5 5
3 2 4
2 3 7 9
3 1 3
3 4 7
Sample Output
2
35
8
35
8
HINT
【样例说明】
初始时数列为(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。
测试数据规模如下表所示
数据编号 1 2 3 4 5 6 7 8 9 10
N= 10 1000 1000 10000 60000 70000 80000 90000 100000 100000
M= 10 1000 1000 10000 60000 70000 80000 90000 100000 100000
线段树的模板题, 注意取模
1 //2018年2月22日12:28:56 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 int n, m, mo; 9 int A[410000], B[410000], sum[410000], size[410000]; 10 11 void change(int k1){ 12 sum[k1] = (sum[k1*2]+sum[k1*2+1]) % mo; 13 } 14 15 void buildtree(int k1, int l, int r){ 16 size[k1] = r-l+1; B[k1] = 1; 17 if(l == r){ 18 scanf("%d", &sum[k1]); return; 19 } 20 int mid = (l+r) >> 1; 21 buildtree(k1*2, l, mid); 22 buildtree(k1*2+1, mid+1, r); 23 change(k1); 24 } 25 26 void add(int k1, int x){ 27 A[k1] = (A[k1]+x) % mo; 28 sum[k1] = (sum[k1]+1ll*size[k1]*x) % mo; 29 } 30 31 void chen(int k1, int x){ 32 A[k1] = 1ll*A[k1]*x % mo; 33 B[k1] = 1ll*B[k1]*x % mo; 34 sum[k1] = 1ll * sum[k1]*x % mo; 35 } 36 37 void pushdown(int k1){ 38 if(B[k1] != 1){ 39 chen(k1*2, B[k1]); 40 chen(k1*2+1, B[k1]); B[k1] = 1; 41 } 42 if(A[k1]){ 43 add(k1*2, A[k1]); 44 add(k1*2+1, A[k1]); 45 A[k1] = 0; 46 } 47 } 48 49 void add(int k1, int l, int r, int L, int R, int x){ 50 if(l>R || r<L) return; 51 if(l>=L && r<=R){ 52 add(k1, x); 53 return; 54 } 55 int mid = (l+r) >> 1; 56 pushdown(k1); 57 add(k1*2, l, mid, L, R, x); 58 add(k1*2+1, mid+1, r, L, R, x); 59 change(k1); 60 } 61 62 void chen(int k1, int l, int r, int L, int R, int x){ 63 if(l>R || r<L) return; 64 if(l>=L && r<=R){ 65 chen(k1, x); return; 66 } 67 int mid = l+r >> 1; 68 pushdown(k1); 69 chen(k1*2, l, mid, L, R, x); 70 chen(k1*2+1, mid+1, r, L, R, x); 71 change(k1); 72 } 73 74 int find(int k1, int l, int r, int L, int R){ 75 if(l>R || r<L) return 0; 76 if(l>=L && r<=R) return sum[k1]; 77 int mid = l+r >> 1; 78 pushdown(k1); 79 return (find(k1*2,l,mid,L,R) + find(k1*2+1,mid+1,r,L,R) ) % mo; 80 } 81 82 int main(){ 83 scanf("%d%d", &n, &mo); 84 buildtree(1, 1, n); 85 scanf("%d", &m); 86 for(; m; m--){ 87 int k1, k2, k3; 88 scanf("%d%d%d", &k1, &k2, &k3); 89 if(k1 == 2){ 90 int k4; scanf("%d", &k4); add(1, 1, n, k2, k3, k4); 91 }else if(k1 == 1){ 92 int k4; scanf("%d", &k4); chen(1, 1, n, k2, k3, k4); 93 }else printf("%d\n", find(1, 1, n, k2, k3)); 94 } 95 96 return 0; 97 }