bzoj1798: [Ahoi2009]Seq 维护序列seq 2011-12-20

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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.

 

以上是关于bzoj1798: [Ahoi2009]Seq 维护序列seq 2011-12-20的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1798: [Ahoi2009]Seq 维护序列seq(线段树)

BZOJ1798 [Ahoi2009]Seq 维护序列seq

bzoj 1798 [Ahoi2009]Seq 维护序列seq(线段树+传标)

bzoj1798: [Ahoi2009]Seq 维护序列seq(线段树多重标记下传)

BZOJ 1798 [Ahoi2009]Seq 维护序列seq

bzoj1798: [Ahoi2009]Seq 维护序列seq