bzoj1798: [Ahoi2009]Seq 维护序列seq 2011-12-20
1798: [Ahoi2009]Seq 维护序列seq
Time Limit: 30 Sec Memory Limit: 64 MB
Submit: 497 Solved: 203
[Submit][Status][Discuss]
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
Sample Output
2
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。
测试数据规模如下表所示
数据编号12345678910
N=10100010001000060000700008000090000100000100000
M=10100010001000060000700008000090000100000100000
Source
Day1
_____________________________________
蛋疼的题啊,状态修改和传递比较烦躁,注意边界大小和取模操作。
_____________________________________
1 Program Stone; 2 3 var t,lc,rc,m:longint; 4 5 a:array[1..100000]of int64; 6 7 ans,tagtime,tagadd,n,q:int64; 8 9 ti,ad,s:array[1..1000000]of int64; 10 11 //s表示该段区间的等待被计算的值,ti表示乘数,ad表示加数。每段区间的和即为 sum=s[i]*ti[i]+ad[i] 12 13 function work(num,head,tail:longint):int64; //计算区间的和 14 15 begin 16 17 work:=((s[num]*ti[num]mod q)+(ad[num]*(tail-head+1))mod q)mod q; 18 19 end; 20 21 procedure lord(num,head,tail:longint); //将乘数和加数传递给子区间。 22 23 begin 24 25 if ti[num]<>1 then begin 26 27 s[num]:=(s[num]*ti[num])mod q; 28 29 ti[num*2]:=(ti[num*2]*ti[num])mod q; 30 31 ad[num*2]:=(ad[num*2]*ti[num])mod q; //子区间的加数需要乘上父区间的乘数。 32 33 ti[num*2+1]:=(ti[num*2+1]*ti[num])mod q; 34 35 ad[num*2+1]:=(ad[num*2+1]*ti[num])mod q; 36 37 ti[num]:=1; //改变乘数。 38 39 end; 40 41 if ad[num]<>0 then begin 42 43 s[num]:=(s[num]+(ad[num]*(tail-head+1))mod q)mod q; 44 45 ad[num*2]:=(ad[num*2]+ad[num])mod q; 46 47 ad[num*2+1]:=(ad[num*2+1]+ad[num])mod q; 48 49 ad[num]:=0; 50 51 end; 52 53 end; 54 55 56 57 procedure update(head,tail,num:longint); 58 59 var k:longint; 60 61 begin 62 63 if (lc<=head)and(tail<=rc) then 64 65 begin 66 67 ti[num]:=(ti[num]*tagtime)mod q; //修改该区间乘数 68 69 ad[num]:=(ad[num]*tagtime+tagadd)mod q; //修改加数 70 71 exit; 72 73 end; 74 75 k:=(head+tail)div 2; 76 77 lord(num,head,tail); //传递 78 79 if k>=lc then update(head,k,num*2); 80 81 if k<rc then update(k+1,tail,num*2+1); 82 83 s[num]:=(work(num*2,head,k)+work(num*2+1,k+1,tail))mod q; //计算区间和 84 85 end; 86 87 88 89 90 91 procedure query(head,tail,num:longint); //询问 92 93 var k:longint; 94 95 begin 96 97 if (lc<=head)and(tail<=rc) then 98 99 begin 100 101 ans:=(ans+work(num,head,tail))mod q; //加上答案 102 103 exit; 104 105 end; 106 107 k:=(head+tail)div 2; 108 109 lord(num,head,tail); 110 111 if k>=lc then query(head,k,num*2); 112 113 if k<rc then query(k+1,tail,num*2+1); 114 115 s[num]:=(work(num*2,head,k)+work(num*2+1,k+1,tail))mod q; 116 117 end; 118 119 120 121 procedure built(head,tail,num:longint); //建树,初始线段树。 122 123 var i,j,k:longint; 124 125 begin 126 127 ti[num]:=1;ad[num]:=0; //初始 128 129 if head=tail then s[num]:=a[head] mod q 130 131 else begin 132 133 k:=(head+tail)div 2 ; 134 135 built(head,k,num*2); 136 137 built(k+1,tail,num*2+1); 138 139 s[num]:=(s[num*2]+s[num*2+1])mod q; 140 141 end; 142 143 end; 144 145 procedure init; 146 147 var i,j,k:longint; 148 149 begin 150 151 readln(n,q); 152 153 for i:=1 to n do read(a[i]); 154 155 built(1,n,1); 156 157 readln(m); 158 159 for i:=1 to m do 160 161 begin 162 163 read(t,lc,rc); 164 165 if t=3 then begin 166 167 readln; 168 169 ans:=0; 170 171 query(1,n,1); 172 173 writeln(ans); 174 175 end; 176 177 if t=1 then begin 178 179 readln(tagtime); //表示乘数 180 181 tagadd:=0; //表示加数 182 183 update(1,n,1); 184 185 end; 186 187 if t=2 then begin 188 189 readln(tagadd); 190 191 tagtime:=1; 192 193 update(1,n,1); 194 195 end; 196 197 end; 198 199 end; 200 201 Begin 202 203 assign(input,'input.in');reset(input); 204 205 init; 206 207 close(input); 208 209 end.