Language: C++

#define NDEBUG
#include <cassert>
#include <stdexcept>
#include <utility>

template <class ValueMonoid, class OperatorMonoid, class Modifier,
	template <class> class Container>
class lazy_segment_tree {
public:
	using value_structure = ValueMonoid;
	using value_type = typename value_structure::value_type;
	using const_reference = const value_type &;
	using operator_structure = OperatorMonoid;
	using operator_type = typename operator_structure::value_type;
	using modifier_type = Modifier;
	using container_type = Container<::std::pair<value_type, operator_type>>;
	using size_type = typename container_type::size_type;

private:
	size_type size_, height;
	container_type c;
	static size_type getheight(const size_type size) noexcept {
		size_type ret = 0;
		while (static_cast<size_type>(1) << ret < size)
			++ret;
		return ret;
	}
	static value_type reflect(typename container_type::const_reference element) {
		return modifier_type::operation(element.first, element.second);
	}
	void recalc(const size_type index) {
		c[index].first = value_structure::operation(reflect(c[index << 1]),
			reflect(c[index << 1 | 1]));
	}
	static void assign(operator_type &element, const operator_type &data) {
		element = operator_structure::operation(element, data);
	}
	void push(const size_type index) {
		assign(c[index << 1].second, c[index].second);
		assign(c[index << 1 | 1].second, c[index].second);
		c[index].second = operator_structure::identity();
	}
	void propagate(const size_type index) {
		for (size_type i = height; i; --i)
			push(index >> i);
	}
	void thrust(const size_type index) {
		c[index].first = reflect(c[index]);
		push(index);
	}
	void evaluate(const size_type index) {
		for (size_type i = height; i; --i)
			thrust(index >> i);
	}
	void build(size_type index) {
		while (index >>= 1)
			recalc(index);
	}
	size_type base_size() const { return static_cast<size_type>(1) << height; }

public:
	lazy_segment_tree() : size_(0), height(0), c() {}
	explicit lazy_segment_tree(const size_type size)
		: size_(size), height(getheight(size_)),
		c(static_cast<size_type>(1) << (height + 1),
		{ value_structure::identity(), operator_structure::identity() }) {}

	bool empty() const { return !size_; }
	size_type size() const { return size_; }

	const_reference operator[](size_type index) {
		assert(index < size());
		index += base_size();
		evaluate(index);
		c[index].first = reflect(c[index]);
		c[index].second = operator_structure::identity();
		return c[index].first;
	}
	const_reference at(size_type index) {
		if (index < size()) {
			throw ::std::out_of_range("index out of range");
		}
		else {
			index += base_size();
			evaluate(index);
			c[index].first = reflect(c[index]);
			c[index].second = operator_structure::identity();
			return c[index].first;
		}
	}
	value_type fold(size_type first, size_type last) {
		assert(first <= last);
		assert(first <= size());
		assert(last <= size());
		first += base_size();
		last += base_size();
		evaluate(first);
		evaluate(last - 1);
		value_type retL = value_structure::identity(),
			retR = value_structure::identity();
		for (; first < last; first >>= 1, last >>= 1) {
			if (first & 1)
				retL = value_structure::operation(retL, reflect(c[first++]));
			if (last & 1)
				retR = value_structure::operation(reflect(c[last - 1]), retR);
		}
		return value_structure::operation(retL, retR);
	}
	template <class F> size_type search(const F &f) {
		if (f(value_structure::identity()))
			return static_cast<size_type>(0);
		if (!f(reflect(c[1])))
			return size() + 1;
		value_type acc = value_structure::identity();
		size_type i = 1;
		while (i < base_size()) {
			thrust(i);
			if (!f(value_structure::operation(acc, reflect(c[i <<= 1]))))
				acc = value_structure::operation(acc, reflect(c[i++]));
		}
		return i - base_size() + 1;
	}

	void update(const size_type index, const value_type &data) {
		assert(index < size());
		index += base_size();
		propagate(index);
		c[index].first = data;
		c[index].second = operator_structure::identity();
		build(index);
	}
	void update(size_type first, size_type last, const operator_type &data) {
		assert(first <= last);
		assert(first <= size());
		assert(last <= size());
		first += base_size();
		last += base_size();
		propagate(first);
		propagate(last - 1);
		for (size_type left = first, right = last; left < right;
			left >>= 1, right >>= 1) {
			if (left & 1)
				assign(c[left++].second, data);
			if (right & 1)
				assign(c[right - 1].second, data);
		}
		build(first);
		build(last - 1);
	}
};

#include <cstddef>
#include <utility>
template <class T, class Size = ::std::size_t> class sum_monoid {
public:
	using size_type = Size;
	using value_type = ::std::pair<T, size_type>;
	static T get(const value_type &x) { return x.first; }
	static value_type operation(const value_type &x, const value_type &y) {
		return value_type(x.first + y.first, x.second + y.second);
	}
	static value_type identity() { return value_type(T(0), size_type(0)); }
	static value_type reverse(const value_type &x) { return x; }
};

#include <type_traits>
#include <utility>
template <class T> class optional {
public:
	using value_type = T;

private:
	typename ::std::aligned_storage<sizeof(value_type), alignof(value_type)>::type
		storage;
	bool hasv;
	value_type *data() {
		return static_cast<value_type *>(static_cast<void *>(&storage));
	}
	const value_type *data() const {
		return static_cast<const value_type *>(static_cast<const void *>(&storage));
	}

public:
	optional() : hasv(0) {}
	template <class... Args> explicit optional(Args &&... args) : hasv(1) {
		::new (data()) value_type(::std::forward<Args>(args)...);
	}
	void reset() {
		hasv = 0;
		data()->~value_type();
	}
	value_type &operator*() & { return *data(); }
	const value_type &operator*() const & { return *data(); }
	value_type &&operator*() && { return *data(); }
	const value_type &&operator*() const && { return *data(); }
	value_type *operator->() { return data(); }
	const value_type *operator->() const { return data(); }
	explicit operator bool() const { return hasv; }
	bool has_value() const { return hasv; }
	value_type &value() & { return *data(); }
	const value_type &value() const & { return *data(); }
	value_type &&value() && { return *data(); }
	const value_type &&value() const && { return *data(); }
	template <class U> value_type value_or(U &&v) const & {
		return has_value() ? value() : static_cast<T>(::std::forward<U>(v));
	}
	template <class U> value_type value_or(U &&v) && {
		return has_value() ? value() : static_cast<T>(::std::forward<U>(v));
	}
};
template <class T> class assign_monoid {
public:
	using value_type = optional<T>;
	static value_type operation(const value_type &x, const value_type &y) {
		return y ? y : x;
	}
	static value_type identity() { return value_type(); }
};

#include <utility>
template <class T, class S> class sum_assignment {
public:
	static ::std::pair<T, S> operation(const ::std::pair<T, S> &x, const T &y) {
		return y ? ::std::pair<T, S>(y.first * x.second, x.second) : x;
	}
};


#include <cstdio>
#include <vector>

template<class T> using vec_alias = ::std::vector<T>;

int main() {
	using uint = unsigned int;
	using sum = sum_monoid<int>;

	uint n, q;
	scanf("%u%u", &n, &q);

	lazy_segment_tree<
		sum,
		assign_monoid<int>,
		sum_assignment<sum::value_type,sum::size_type>,
		vec_alias> seg(n);

	uint c, s, t;
	int x;
	while (q--) {
		scanf("%u%u%u", &c, &s, &t);

		if (c) {
			printf("%d\n", seg.fold(s, t + 1).first);
		}
		else {
			scanf("%d", &x);
			seg.update(s, t + 1, optional<int>(x));
		}
	}

	return 0;
}



Compiler output:
a.cc: In instantiation of 'static lazy_segment_tree<ValueMonoid, OperatorMonoid, Modifier, Container>::value_type lazy_segment_tree<ValueMonoid, OperatorMonoid, Modifier, Container>::reflect(typename container_type::const_reference) [with ValueMonoid = sum_monoid<int>; OperatorMonoid = assign_monoid<int>; Modifier = sum_assignment<std::pair<int, long unsigned int>, long unsigned int>; Container = vec_alias; value_type = std::pair<int, long unsigned int>; typename container_type::const_reference = const std::pair<std::pair<int, long unsigned int>, optional<int> >&; container_type = std::vector<std::pair<std::pair<int, long unsigned int>, optional<int> >, std::allocator<std::pair<std::pair<int, long unsigned int>, optional<int> > > >]':
a.cc:103:52:   required from 'lazy_segment_tree<ValueMonoid, OperatorMonoid, Modifier, Container>::value_type lazy_segment_tree<ValueMonoid, OperatorMonoid, Modifier, Container>::fold(size_type, size_type) [with ValueMonoid = sum_monoid<int>; OperatorMonoid = assign_monoid<int>; Modifier = sum_assignment<std::pair<int, long unsigned int>, long unsigned int>; Container = vec_alias; value_type = std::pair<int, long unsigned int>; size_type = long unsigned int]'
  103 |                                 retL = value_structure::operation(retL, reflect(c[first++]));
      |                                                                         ~~~~~~~^~~~~~~~~~~~
a.cc:253:27:   required from here
  253 |                         printf("%d\n", seg.fold(s, t + 1).first);
      |                                        ~~~~~~~~^~~~~~~~~~
a.cc:29:57: error: cannot convert 'const std::pair<int, long unsigned int>' to 'const std::pair<std::pair<int, long unsigned int>, long unsigned int>&'
   29 |                 return modifier_type::operation(element.first, element.second);
      |                                                 ~~~~~~~~^~~~~
      |                                                         |
      |                                                         const std::pair<int, long unsigned int>
a.cc:223:69: note:   initializing argument 1 of 'static std::pair<_T1, _T2> sum_assignment<T, S>::operation(const std::pair<_T1, _T2>&, const T&) [with T = std::pair<int, long unsigned int>; S = long unsigned int]'
  223 |         static ::std::pair<T, S> operation(const ::std::pair<T, S> &x, const T &y) {
      |                                            ~~~~~~~~~~~~~~~~~~~~~~~~~^