14543. Range Sum

 

You are initially given an array of n integers (1 ≤ n ≤ 105). Given this array, you have to perform 2 kinds of operations :

 

(i) Operation 1 : Op1(l, r)

You are given 2 integers l and r (1 ≤ lr ≤ current size of the array). You need to return the sum of all the elements with indices between l and r (both inclusive). That is, if the elements currently in the array are a1, a2, a3.... an, you need to return the following sum: al + al+1 + al+2 ... + ar.

 

(ii) Operation 2 : Op2(x)

You are given a single integer x (|x| ≤ 109). Add this element to the beginning of the array. After this operation, x will now become a, the old a1 will now become a2, and so on. The size of the array will increase by 1.

 

Input. The first line contains a single integer n (1 n 105), the number of elements initially in the array.

This is followed by a line containing n space separated integers a1 a2 .... an ( |ai| 109).

The next line contains a single integer q, the number of operations you will be asked to perform ( 1 q 105).

q lines of input follow. Each such line starts with either the number 1 or the number 2. This indicates the type of operation that you are required to perform. The format of these queries are as follows :

·        1 l r : Carry out operation 1 with arguments l and r ( 1 l r current size of the array). That is, return the sum of the following array elements : al + al+1 ... + ar

·        2 x : Carry out operation 2 with the argument x ( |x| 109). That is, add the value x at the beginning of the array.

 

Output. For each query of type 1, output the return value on a new line. No output needs to be printed for queries of type 2.

 

Sample Input 1

Sample Output 1

10

1 2 3 4 5 6 7 8 9 10

4

1 1 10

1 1 1

1 10 10

1 2 7

55

1

10

27

 

 

Sample Input 2

Sample Output 2

5

6 7 8 9 10

9

2 5

2 4

1 2 7

2 3

2 2

2 1

1 1 10

1 1 1

1 10 10

45

55

1

10

 

 

РЕШЕНИЕ

дерево отрезков

 

Анализ алгоритма

Объявим массив длины 2n. Во вторую его половину занесем последовательность a1 a2 .... an. Первую половину заполним нулями. Построим по этому массиву дерево отрезков. При каждой операции типа 2 слева к имеющемуся массиву будем приписывать новое число (новое число занимает место нуля).

В тестах количество запрсов типа 2 не превосходит n.

 

Реализация алгоритма

 

#include <cstdio>

#include <vector>

#include <algorithm>

#define MAX 200010

using namespace std;

 

vector<long long> SegTree(4*MAX,0);

 

void BuildTree(vector<long long>&a, int Vertex,

               int LeftPos, int RightPos)

{

  if (LeftPos == RightPos)

    SegTree[Vertex] = a[LeftPos];

  else

  {

    int Middle = (LeftPos + RightPos) / 2;

    BuildTree(a, 2*Vertex, LeftPos, Middle);

    BuildTree(a, 2*Vertex+1, Middle+1, RightPos);

    SegTree[Vertex] = SegTree[2*Vertex] + SegTree[2*Vertex+1];

  }

}

 

long long Summa(int Vertex, int LeftPos, int RightPos,

                int Left, int Right)

{

  if (Left > Right) return 0;

  if ((Left == LeftPos) && (Right == RightPos))

    return SegTree[Vertex];

 

  int Middle = (LeftPos + RightPos) / 2;

  return Summa(2*Vertex, LeftPos, Middle, Left, min(Right,Middle)) +

     Summa(2*Vertex+1, Middle+1, RightPos, max(Left,Middle+1), Right);

}

 

void update(int Vertex, int LeftPos, int RightPos,

            int Position, long long NewValue)

{

  if (LeftPos == RightPos)

    SegTree[Vertex] = NewValue;

  else

  {

    int Middle = (LeftPos + RightPos) / 2;

    if (Position <= Middle)

      update (2*Vertex, LeftPos, Middle, Position, NewValue);

    else update (2*Vertex+1, Middle+1, RightPos, Position, NewValue);

    SegTree[Vertex] = SegTree[2*Vertex] + SegTree[2*Vertex+1];

  }

}

 

vector<long long> v;

int n, q, i, j, l, r;

int type, start;

 

int main(void)

{

  scanf("%d",&n);

  start = n + 1;

  v.resize(start + n);

  for(i = 0; i < n; i++)

    scanf("%lld",&v[start + i]);

 

  BuildTree(v,1,1,2*n);

 

  scanf("%d",&q);

  for(j = 0; j < q; j++)

  {

    scanf("%d",&type);

    if (type == 1)

    {

      scanf("%d %d",&l,&r);

      printf("%lld\n",Summa(1,1,2*n,start-1+l,start-1+r));

 

    } else

    {

      scanf("%d",&v[--start]);

      update(1,1,2*n,start,v[start]);

    }

  }

  return 0;

}