poj3468 A Simple Problem with Integers——线段树的应用

 

A Simple Problem with Integers

 

Time Limit: 5000MS Memory Limit: 131072K
Total Submissions: 16883 Accepted: 4349
Case Time Limit: 2000MS

 

Description

You haveNintegers,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 numbersNandQ. 1 ≤N,Q≤ 100000.
The second line containsNnumbers, the initial values ofA1,A2, ... ,AN. -1000000000 ≤Ai≤ 1000000000.
Each of the nextQlines represents an operation.
"Cabc" means addingcto each ofAa,Aa+1, ... ,Ab. -10000 ≤c≤ 10000.
"Qab" means querying the sum ofAa,Aa+1, ... ,Ab.

Output

You need to answer allQcommands 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

The sums may exceed the range of 32-bit integers.

Source

题目大意:给出一个区间,1~n,有m个操作,每一个操作可能是:“I”——“a,b,c”——插入——在区间中的a到b每一个数都加一个数c;“Q”——“a,b”——求和——输出区间a到b的和。
小结:看到区间问题,首先应该想到线段树,而求和又是线段树的基本操作。题目中要求比较不同的就是对于区间的每一个数都加一个数,如果直接对每一个数都进行一次加法运算,那么效率将是很低的。这里应用到一种称之为“lazy”的思想:对于一个区间,给它标记一个数值data,比如题目中的区间每一个数的增量,这个值就代表区间的每一个值都需要加上这个值。当我们需要处理这个区间时,就将这个数值data分配给两个儿子,而自己的data值变成0.对于其他的以区间为单位的基本操作也可以采用这种lazy思想,需要拆分时将它分开传递给两份儿子。
 
type

  ji=^rec;

  rec=record

  sum,add:int64;

  l,r:longint;

  lson,rson:ji;

end;

var

  a:ji;

  ch:char;

  b:array[0..100005] of int64;

  i,j,k,m,n,s,t:longint;

procedure build(var a:ji; l,r:longint);

begin

  new(a); a^.l:=l; a^.r:=r;

  if r>l then

    begin

      build(a^.lson,l,(l+r)>>1);

      build(a^.rson,(l+r)>>1+1,r);

      a^.add:=0;

      a^.sum:=a^.lson^.sum+a^.rson^.sum;

    end

  else

    begin

      a^.sum:=b[l];

      a^.add:=0;

      a^.lson:=nil;

      a^.rson:=nil;

    end;

end;



procedure insert(var a:ji; l,r,s:longint);

var

  mid:longint;

begin

  if (a^.l>=l)and(a^.r<=r) then

    begin

      inc(a^.add,s);

      exit;

    end;

  mid:=(a^.l+a^.r)>>1;

  if l<=mid then insert(a^.lson,l,r,s);

  if r>mid  then insert(a^.rson,l,r,s);

  a^.sum:=a^.lson^.sum+a^.lson^.add*(a^.lson^.r-a^.lson^.l+1);

  inc(a^.sum,a^.rson^.sum+a^.rson^.add*(a^.rson^.r-a^.rson^.l+1));

end;



function count(var a:ji; l,r:longint):int64;

var

  mid:longint;

  ans:int64;

begin

  ans:=0;

  if (l<=a^.l)and(r>=a^.r) then

    begin

      inc(ans,a^.sum+a^.add*(a^.r-a^.l+1));

      exit(ans);

    end;

  if a^.lson<>nil then inc(a^.lson^.add,a^.add);

  if a^.rson<>nil then inc(a^.rson^.add,a^.add);

  a^.add:=0;

  mid:=(a^.l+a^.r)>>1;

  if l<=mid then ans:=ans+count(a^.lson,l,r);

  if r>mid  then ans:=ans+count(a^.rson,l,r);

  a^.sum:=a^.lson^.sum+a^.rson^.sum+a^.lson^.add*(a^.lson^.r-a^.lson^.l+1);

  inc(a^.sum,a^.rson^.add*(a^.rson^.r-a^.rson^.l+1));

  exit(ans);

end;



begin

  readln(n,m);

  for i:=1 to n do read(b[i]); readln;

  build(a,1,n);

  for i:=1 to m do

    begin

      read(ch,s,t);

      if ch='C' then

        begin

          read(k);

          insert(a,s,t,k);

        end

      else

        begin

          writeln(count(a,s,t));

        end;

      readln;

    end;

end.

你可能感兴趣的:(Integer)