#include <vector>
#include <cassert>
#include <functional>

template<typename T, typename E>
struct LazySegmentTree {
	using value_type = T;
	using lazy_type = E;
	using size_type = std::size_t;
	using F = std::function<value_type(const value_type &, const value_type &)>; // 要素の merge
	using G = std::function<value_type(const value_type &, const lazy_type &)>; // 要素に作用素を作用
	using H = std::function<lazy_type(const lazy_type &, const lazy_type &)>; // 作用素の merge
	using P = std::function<lazy_type(const lazy_type &, size_type)>; // 区間への作用がその区間の大きさ(k) に比例して変化するとき p(a, k) := g(a, a, ..., a) (k 個)
	
private:
	size_type n;
	F f;
	G g;
	H h;
	P p;
	value_type id_node;
	lazy_type id_lazy;
	std::vector<value_type> node;
	std::vector<lazy_type> lazy;

public:
	LazySegmentTree(size_type n_, const value_type & id_node, const lazy_type & id_lazy, const F & f, const G & g, const H & h, const P & p = [](const lazy_type & a, size_type l) { return a; })
			: n(n), id_node(id_node), id_lazy(id_lazy), f(f), g(g), h(h), p(p) {
		n = 1;
		while (n < n_) n <<= 1;
		node.resize(2 * n, id_node);
		lazy.resize(2 * n, id_lazy);
	}
	
	LazySegmentTree(const std::vector<value_type> & v, const value_type & id_node, const lazy_type & id_lazy, const F & f, const G & g, const H & h, const P & p = [](const lazy_type & a, size_type l) { return a; })
			: LazySegmentTree(v.size(), id_node, id_lazy, f, g, h, p) {
		for (size_type i = 0; i < v.size(); ++i) node[i + size()] = v[i];
		for (size_type i = size() - 1; i > 0; --i) node[i] = f(node[i << 1], node[i << 1 | 1]);
	}
	
	size_type size() const noexcept {
		return n;
	}
	
	void update(size_type l, size_type r, const lazy_type & x) {
		if (l == r) return;
		assert(l < r);
		assert(r <= size());
		update(l, r, x, 1, 0, size());
	}
	
	value_type fold(size_type l, size_type r) {
		if (l == r) return id_node;
		assert(l < r);
		assert(r <= size());
		return fold(l, r, 1, 0, size());
	}
	
private:
	void eval(size_type k, size_type l) {
		if (lazy[k] == id_lazy) return;
		if ((k << 1 | 1) < node.size()) {
			lazy[k << 1] = h(lazy[k << 1], lazy[k]);
			lazy[k << 1 | 1] = h(lazy[k << 1 | 1], lazy[k]);
		}
		node[k] = g(node[k], p(lazy[k], l));
		lazy[k] = id_lazy;
	}
	
	value_type update(size_type a, size_type b, const lazy_type & x, size_type k, size_type l, size_type r) {
		eval(k, r - l);
		if (l >= b || r <= a) return node[k];
		if (a <= l && r <= b) {
			lazy[k] = h(lazy[k], x);
			return g(node[k], p(lazy[k], r - l));
		}
		return node[k] = f(update(a, b, x, k << 1, l, (l + r) >> 1), update(a, b, x, k << 1 | 1, (l + r) >> 1, r));
	}
	
	value_type fold(size_type a, size_type b, size_type k, size_type l, size_type r) {
		eval(k, r - l);
		if (l >= b || r <= a) return id_node;
		if (a <= l && r <= b) return node[k];
		return f(fold(a, b, k << 1, l, (l + r) >> 1), fold(a, b, k << 1 | 1, (l + r) >> 1, r));
	}
};

#include <cstdio>

int main() {
	using ll = long long;
	int N, Q;
	scanf("%d %d", &N, &Q);
	
	struct Data {
		int c0, c1;
		ll inversion;
	};
	
	std::vector<Data> A(N);
	for (int i = 0; i < N; ++i) {
		int a;
		scanf("%d", &a);
		A[i] = Data{a == 0, a == 1, 0};
	}
	
	LazySegmentTree<Data, bool> seg(A, Data{0, 0, 0}, false,
		[](auto && a, auto && b) { return Data{a.c0 + b.c0, a.c1 + b.c1, a.inversion + b.inversion + (ll)a.c1 * b.c0}; },
		[](auto && a, bool b) { return Data{a.c1, a.c0, (ll)a.c1 * a.c0 - a.inversion}; },
		[](bool a, bool b) { return a ^ b; });
	
	while (Q--) {
		int t, l, r;
		scanf("%d %d %d", &t, &l, &r);
		if (t == 1) seg.update(l - 1, r, true);
		else printf("%lld\n", seg.fold(l - 1, r).inversion);
	}
}

Measured memory_bytes: 14076