The sum#2307

The sum (Editorial)

To solve the problem, it is necessary to implement a segment tree that supports range operations — assignment and summation.

In each node of the tree, the variable stores the value assigned to all elements of the segment corresponding to that node. If a node represents the segment [l; r], then the sum of the elements on this segment is equal to add \cdot (r - l + 1).

When performing assignment and summation operations, while descending the tree from the root to the leaves, the value of in each node must be pushed down to the next level of the tree.

When an assignment operation is performed, the previous sum values in the child nodes s_1 and s_2, as well as the pending assignment values a_1 and a_2, are discarded.

During the construction of the segment tree, the variable in each node is initialized with a value that will never be assigned to the elements of any segment (for example, ).

Algorithm implementation

The segment tree is stored as an array SegTree, whose elements are of type . Each node of the tree corresponds to a certain segment of the array and stores information about that segment.

The structure contains two fields:

The constructor is called automatically when each node of the tree is created:

struct node
{
  long long sum, add;
  node() : sum(0), add(-1) {}
};
vector<node> SegTree;

The function Push propagates the value from node to its child nodes. If add \ne -1, this value must be pushed down one level in the tree. After the propagation is completed, the value of in node is set to .

void Push(int v, int lpos, int mid, int rpos)
{

If add = -1, then there is no pending operation in node .

  if (SegTree[v].add == -1) return;

Recompute the values of and in the child nodes of node .

  SegTree[2*v].add = SegTree[v].add;
  SegTree[2*v].sum = (mid - lpos + 1) * SegTree[v].add;
  SegTree[2*v+1].add = SegTree[v].add;
  SegTree[2*v+1].sum = (rpos - mid) * SegTree[v].add;

After the propagation is completed, set add = -1 in node .

  SegTree[v].add = -1;
}

The function SetValue assigns the value to all elements in the segment [left; right]. Node corresponds to the segment [lpos; rpos].

void SetValue(int v, int lpos, int rpos, int left, int right, int val)
{
    if (left > right) return;

If the segment [left; right] corresponds to the segment [lpos; rpos] stored in the tree node, then we assign the appropriate values to the variables and in this node.

  if ((lpos == left) && (rpos == right))
  {

    SegTree[v].add = val;
    SegTree[v].sum = (long long)(right - left + 1) * val;
    return;
  }

Find the midpoint of the segment: mid = (lpos + rpos) / 2.

  int mid = (lpos + rpos) / 2;

Perform propagation if is not equal to .

  Push(v, lpos, mid, rpos);

Recursively process the left and right child nodes of the current segment tree node.

  SetValue(2*v, lpos, mid, left, min(mid, right), val);
  SetValue(2*v+1, mid+1, rpos, max(left, mid+1), right, val);

Recompute the sum value in node using the sum values of its children.

  SegTree[v].sum = SegTree[2*v].sum + SegTree[2*v+1].sum;
}

The function Summa returns the sum of the elements in the segment [left; right].Node corresponds to the segment [lpos; rpos].

long long Summa(int v, int lpos, int rpos, int left, int right)
{
  if (left > right) return 0;

If the segment [left; right] coincides with the segment [lpos; rpos] stored in node of the tree, return the sum value stored in this node.

  if ((lpos == left) && (rpos == right)) 
    return SegTree[v].sum;

Find the midpoint of the segment: mid = (lpos + rpos) / 2.

  int mid = (lpos + rpos) / 2;

Perform propagation if is not equal to .

  Push(v, lpos, mid, rpos);

Split the segment [lpos; rpos] into two subsegments: [lpos; mid] and [mid + 1; rpos]. Recursively compute the sums on these subsegments and add the obtained values.

  return Summa(2*v, lpos, mid, left, min(mid, right)) +
         Summa(2*v+1, mid+1, rpos, max(left, mid+1), right);
}

The main part of the program. Read the input data and initialize the segment tree.

cin >> n >> k;
SegTree.resize(4 * n);

Process queries. Depending on the type of query, we either perform a range assignment or compute the sum over the specified segment.

while (k--)
{
  cin >> c;
  if (c == 'A')
  {
    cin >> l >> r >> x;
    SetValue(1, 1, n, l, r, x);
  }
  else
  {
    cin >> l >> r;
    cout << Summa(1, 1, n, l, r) << endl;
  }
}