Problem:
RSQ and RUQ

Write a program which manipulates a sequence $A$ = {$a_0, a_1, ..., a_{n-1}$} with the following operations:

$update(s, t, x)$: change $a_s, a_{s+1}, ..., a_t$ to $x$.

$getSum(s, t)$: print the sum of $a_s, a_{s+1}, ..., a_t$.

Note that the initial values of $a_i ( i = 0, 1, ..., n-1 )$ are 0.

Input

$n$ $q$
$query_1$
$query_2$
:
$query_q$

In the first line, $n$ (the number of elements in $A$) and $q$ (the number of queries) are given. Then, $i$-th query $query_i$ is given in the following format:

0 $s$ $t$ $x$

or

1 $s$ $t$

The first digit represents the type of the query. '0' denotes $update(s, t, x)$
and '1' denotes $find(s, t)$.

Output

For each $getSum$ query, print the sum in a line.

Constraints

$1 ≤ n ≤ 100000$

$1 ≤ q ≤ 100000$

$0 ≤ s ≤ t < n$

$-1000 ≤ x ≤ 1000$

Sample Input 1

6 7
0 1 3 1
0 2 4 -2
1 0 5
1 0 1
0 3 5 3
1 3 4
1 0 5

Sample Output 1

-5
1
6
8

Solution in C# (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Text;
using CompLib.DataStructures;

public class Program
{
    public void Solve()
    {
        var sc = new Scanner();
        int n = sc.NextInt();
        int q = sc.NextInt();

        var st = new LazySegmentTreeRsq(n);
        var sb = new StringBuilder();
        for (int i = 0; i < q; i++)
        {
            string type = sc.Next();
            if (type == "0")
            {
                int s = sc.NextInt();
                int t = sc.NextInt();
                int x = sc.NextInt();
                st.Update(s, t + 1, x);
            }
            else
            {
                int s = sc.NextInt();
                int t = sc.NextInt();
                sb.AppendLine(st.Sum(s, t + 1).ToString());
            }
        }

        Console.Write(sb.ToString());
    }

    public static void Main(string[] args)
    {
        new Program().Solve();
    }
}

namespace CompLib.DataStructures
{
    #region RangeSumQuery

    using N = Int64;

    /// <summary>
    /// 遅延セグメント木 (RangeSumQuery)
    /// 指定した範囲の和を求める、更新 それぞれO(log N)
    /// </summary>
    public class LazySegmentTreeRsq
    {
        private readonly int _size;
        private readonly N[] _array;
        private readonly N[] _add;
        private readonly N[] _update;
        private readonly bool[] _updateFlag;

        /// <summary>
        /// コンストラクタ
        /// 全て0で初期化
        /// </summary>
        /// <param name="size">配列の大きさ = N</param>
        public LazySegmentTreeRsq(int size)
        {
            _size = 1;
            while (_size < size)
                _size *= 2;
            _array = new N[_size * 2];
            _add = new N[_size * 2];
            _update = new N[_size * 2];
            _updateFlag = new bool[_size * 2];
        }

        /// <summary>
        /// コンストラクタ
        /// 配列aをコピー
        /// </summary>
        /// <param name="a">配列</param>
        public LazySegmentTreeRsq(N[] a) : this(a.Length)
        {
            for (int i = 0; i < a.Length; i++)
                _array[i + _size] = a[i];
            for (int i = _size - 1; i >= 1; i--)
                _array[i] = _array[i * 2] + _array[i * 2 + 1];
        }

        private void Eval(int l, int r, int k)
        {
            if (_updateFlag[k])
            {
                _array[k] = _update[k] * (r - l);
                if (r - l > 1)
                {
                    _update[k * 2] = _update[k];
                    _update[k * 2 + 1] = _update[k];
                    _add[k * 2] = 0;
                    _add[k * 2 + 1] = 0;
                    _updateFlag[k * 2] = true;
                    _updateFlag[k * 2 + 1] = true;
                }

                _updateFlag[k] = false;
            }

            if (_add[k] != 0)
            {
                _array[k] += _add[k] * (r - l);
                if (r - l > 1)
                {
                    _add[k * 2] += _add[k];
                    _add[k * 2 + 1] += _add[k];
                }

                _add[k] = 0;
            }
        }

        private void Add(int left, int right, int k, int l, int r, N n)
        {
            Eval(l, r, k);
            if (r <= left || right <= l) return;
            if (left <= l && r <= right)
            {
                _add[k] += n;
                Eval(l, r, k);
            }
            else
            {
                Add(left, right, k * 2, l, (l + r) / 2, n);
                Add(left, right, k * 2 + 1, (l + r) / 2, r, n);
                _array[k] = _array[k * 2] + _array[k * 2 + 1];
            }
        }

        /// <summary>
        /// [left,right)にnを足す O(log N)
        /// </summary>
        /// <param name="left">左端</param>
        /// <param name="right">右端</param>
        /// <param name="n">増やす値</param>
        public void Add(int left, int right, N n) => Add(left, right, 1, 0, _size, n);

        /// <summary>
        /// i番目にnを足す O(log N)
        /// </summary>
        /// <param name="i">インデックス</param>
        /// <param name="n">増やす値</param>
        public void Add(int i, N n) => Add(i, i + 1, n);

        private void Update(int left, int right, int k, int l, int r, N n)
        {
            Eval(l, r, k);
            if (r <= left || right <= l) return;
            if (left <= l && r <= right)
            {
                _update[k] = n;
                _updateFlag[k] = true;
                _add[k] = 0;
                Eval(l, r, k);
            }
            else
            {
                Update(left, right, k * 2, l, (l + r) / 2, n);
                Update(left, right, k * 2 + 1, (l + r) / 2, r, n);
                _array[k] = _array[k * 2] + _array[k * 2 + 1];
            }
        }

        /// <summary>
        /// [left, right)をnに置き換える
        /// </summary>
        /// <param name="left">右端</param>
        /// <param name="right">左端</param>
        /// <param name="n">置き換える値</param>
        public void Update(int left, int right, N n) => Update(left, right, 1, 0, _size, n);

        /// <summary>
        /// i番目をnに置き換える
        /// </summary>
        /// <param name="i">インデックス</param>
        /// <param name="n">置き換える値</param>
        public void Update(int i, N n) => Update(i, i + 1, n);

        private N Sum(int left, int right, int k, int l, int r)
        {
            Eval(l, r, k);
            if (r <= left || right <= l) return 0;
            if (left <= l && r <= right) return _array[k];
            return Sum(left, right, k * 2, l, (l + r) / 2) + Sum(left, right, k * 2 + 1, (l + r) / 2, r);
        }

        /// <summary>
        /// [left, right)の和を求める O(log N)
        /// </summary>
        /// <param name="left">左端</param>
        /// <param name="right">右端</param>
        /// <returns></returns>
        public N Sum(int left, int right) => Sum(left, right, 1, 0, _size);

        public N this[int i]
        {
            get { return Sum(i, i + 1); }
            set { Update(i, value); }
        }
    }

    #endregion
}

class Scanner
{
    public Scanner()
    {
        _pos = 0;
        _line = new string[0];
    }

    const char Separator = ' ';
    private int _pos;
    private string[] _line;

    #region スペース区切りで取得

    public string Next()
    {
        if (_pos >= _line.Length)
        {
            _line = Console.ReadLine().Split(Separator);
            _pos = 0;
        }

        return _line[_pos++];
    }

    public int NextInt()
    {
        return int.Parse(Next());
    }

    public long NextLong()
    {
        return long.Parse(Next());
    }

    public double NextDouble()
    {
        return double.Parse(Next());
    }

    #endregion

    #region 型変換

    private int[] ToIntArray(string[] array)
    {
        var result = new int[array.Length];
        for (int i = 0; i < array.Length; i++)
        {
            result[i] = int.Parse(array[i]);
        }

        return result;
    }

    private long[] ToLongArray(string[] array)
    {
        var result = new long[array.Length];
        for (int i = 0; i < array.Length; i++)
        {
            result[i] = long.Parse(array[i]);
        }

        return result;
    }

    private double[] ToDoubleArray(string[] array)
    {
        var result = new double[array.Length];
        for (int i = 0; i < array.Length; i++)
        {
            result[i] = double.Parse(array[i]);
        }

        return result;
    }

    #endregion

    #region 配列取得

    public string[] Array()
    {
        if (_pos >= _line.Length)
            _line = Console.ReadLine().Split(Separator);
        _pos = _line.Length;
        return _line;
    }

    public int[] IntArray()
    {
        return ToIntArray(Array());
    }

    public long[] LongArray()
    {
        return ToLongArray(Array());
    }

    public double[] DoubleArray()
    {
        return ToDoubleArray(Array());
    }

    #endregion
}