Time Limit: 5000MS | Memory Limit: 131072K |
Description
You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.
Input
The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of Aa, Aa+1, ... , Ab.
Output
You need to answer all Q commands in order. One answer in a line.
Sample Input
10 5 1 2 3 4 5 6 7 8 9 10 Q 4 4 Q 1 10 Q 2 4 C 3 6 3 Q 2 4
Sample Output
4 55 9 15
Hint
program pku_3468;
var a,sum,size,fa,delta:array[0..100010] of int64;
c:array[0..100010,0..1] of longint;
n,m,root:longint;
//============================================================================
procedure update(x:longint); //每次旋转完跟新节点的两个域。
begin
sum[x]:=sum[c[x,0]]+sum[c[x,1]]+a[x];
size[x]:=size[c[x,0]]+size[c[x,1]]+1; //要把本身加上。
end;
//============================================================================
procedure build(l,r:longint); //一开始先用递归建立伸展数,而不是一个个插入完在splay,这样省空间又省时间,不然有可能暴栈。
var mid,tmp:longint;
begin
mid:=(l+r) shr 1;
if l<mid then
begin
build(l,mid-1);
tmp:=(l+mid-1) shr 1;
c[mid,0]:=tmp; fa[tmp]:=mid;
end;
if mid<r then
begin
build(mid+1,r);
tmp:=(mid+1+r) shr 1;
c[mid,1]:=tmp; fa[tmp]:=mid;
end; update(mid);
end;
//============================================================================
procedure init; //读入。
var i:longint;
begin
readln(n,m);
for i:=2 to n do read(a[i]); readln(a[n+1]);
build(1,n+2); root:=(n+3) shr 1;
end;
//============================================================================
procedure clean(x,k:longint); //从x开始向下推标签,直到k。
begin
repeat
if delta[x]<>0 then
begin
inc(delta[c[x,0]],delta[x]);
inc(delta[c[x,1]],delta[x]);
inc(sum[c[x,0]],size[c[x,0]]*delta[x]);
inc(sum[c[x,1]],size[c[x,1]]*delta[x]);
a[x]:=a[x]+delta[x]; delta[x]:=0;
end;
if x=k then exit;
if x>k then x:=c[x,0] else x:=c[x,1];
until false;
end;
//============================================================================
procedure rotate(var root:longint; x:longint); //旋转x
var y,z,p,q:longint;
begin
y:=fa[x]; z:=fa[y];
if c[y,0]=x then p:=0 else p:=1;
q:=p xor 1;
if y=root then root:=x else
if c[z,0]=y then c[z,0]:=x else c[z,1]:=x;
fa[x]:=z; fa[y]:=x; fa[c[x,q]]:=y;
c[y,p]:=c[x,q]; c[x,q]:=y;
update(y); update(x); //旋转完要记住更新旋转中变动的节点的域。
end;
//============================================================================
procedure splay(var root:longint; x:longint); //重要的splay操作。
var y,z:longint;
begin
while x<>root do
begin
y:=fa[x]; z:=fa[y];
if y<>root then//判断是要双旋或是单旋。
if (c[y,0]=x) xor (c[z,0]=y) then//用异或精炼判断是之字形还是一字型(zc所教Orz。。)
rotate(root,x) else rotate(root,y);
rotate(root,x);
end;
end;
//============================================================================
procedure ask; //询问操作。
var s,t:longint;
begin
readln(s,t); inc(t,2); //实际上是操作l-1和r+1两点。
clean(root,s); clean(root,t); //先推标签。
splay(root,s); splay(c[s,1],t);
writeln(sum[c[t,0]]);
end;
//============================================================================
procedure change; //修改操作。
var s,t,z:longint;
begin
readln(s,t,z); inc(t,2);
clean(root,s); clean(root,t);
splay(root,s); splay(c[s,1],t);
inc(delta[c[t,0]],z); //伸展完可以直接把标签打在根的右节点的左节点上。
inc(sum[c[t,0]],z*size[c[t,0]]); //打完标签要同时修改sum值。
end;
//============================================================================
procedure work;
var i:longint;
ch:char;
begin
for i:=1 to m do
begin
read(ch);
if ch='Q' then ask else change;
end;
end;
//============================================================================
begin
init;
work;
end.