#include <bits/stdc++.h>   using namespace std;   int M;   int next_losing_index(int A, int losing_index) {     return A == 0 || losing_index < M ? min(losing_index + 1, M) : 0;   }   struct segment_change {     bool flip;     segment_change(bool _flip = false) : flip(_flip) {}     void reset() { flip = false; }     segment_change combine(const segment_change &other) const {       return segment_change(flip ^ other.flip);     }   };   struct segment {     vector<int> through, flipped;     segment() {       through.resize(M + 1);       flipped.resize(M + 1);       for (int index = 0; index <= M; index++)         through[index] = flipped[index] = index;     }     void init(int start, int end, int A) {       for (int index = 0; index <= M; index++) {         through[index] = next_losing_index(A, index);         flipped[index] = next_losing_index(A ^ 1, index);       }     }     void apply(int start, int end, const segment_change &change) {       if (change.flip) swap(through, flipped);     }     void join(const segment &other) {       vector<int> next_through(M + 1), next_flipped(M + 1);       for (int index = 0; index <= M; index++) {         next_through[index] = through[other.through[index]];         next_flipped[index] = flipped[other.flipped[index]];       }       through = next_through;       flipped = next_flipped;     }     void join(const segment &a, const segment &b) {       *this = a;       join(b);     }   };   struct seg_tree {     int tree_n;     vector<segment> tree;     vector<segment_change> changes;     seg_tree(int n = 0) {       tree_n = 0;       if (n > 0) init(n);     }     void init(int n) {       tree_n = 1;       while (tree_n < n) tree_n *= 2;       tree.assign(2 * tree_n, segment());       changes.assign(2 * tree_n, segment_change());     }     template <typename T>     void build(const vector<T> &initial) {       int n = initial.size();       assert(n <= tree_n);       for (int i = 0; i < n; i++) tree[tree_n + i].init(i, i + 1, initial[i]);       for (int position = tree_n - 1; position > 0; position--)         tree[position].join(tree[2 * position], tree[2 * position + 1]);     }     void push_down(int position, int start, int mid, int end) {       tree[2 * position].apply(start, mid, changes[position]);       tree[2 * position + 1].apply(mid, end, changes[position]);       changes[2 * position] = changes[2 * position].combine(changes[position]);       changes[2 * position + 1] =           changes[2 * position + 1].combine(changes[position]);       changes[position].reset();     }     template <typename T_range_op, typename T_join_op>     void process_range(int position, int start, int end, int a, int b,                        T_range_op &&range_op, T_join_op &&join_op) {       if (a <= start && end <= b) {         range_op(position, start, end);         return;       }       if (position >= tree_n) return;       int mid = (start + end) / 2;       push_down(position, start, mid, end);       if (a < mid)         process_range(2 * position, start, mid, a, b, range_op, join_op);       if (b > mid)         process_range(2 * position + 1, mid, end, a, b, range_op, join_op);       join_op(position);     }     segment query(int a, int b) {       segment answer;       process_range(           1, 0, tree_n, a, b,           [&](int position, int, int) { answer.join(tree[position]); },           [&](int) {});       return answer;     }     void update(int a, int b, const segment_change &change) {       process_range(           1, 0, tree_n, a, b,           [&](int position, int start, int end) {             tree[position].apply(start, end, change);             changes[position] = changes[position].combine(change);           },           [&](int position) {             tree[position].join(tree[2 * position], tree[2 * position + 1]);           });     }     template <typename T_bool>     int find_last_prefix(int n, T_bool &&should_join) {       segment current;       if (!should_join(current, current)) return -1;       if (should_join(current, tree[1])) return n;       int position = 1;       int start = 0, end = tree_n;       while (position < tree_n) {         int mid = (start + end) / 2;         push_down(position, start, mid, end);         if (should_join(current, tree[2 * position])) {           current.join(tree[2 * position]);           position = 2 * position + 1;           start = mid;         } else {           position = 2 * position;           end = mid;         }       }       assert(position == tree_n + start);       assert(0 <= start && start < n);       assert(end - start == 1);       return start;     }   };   int N, Q;   vector<int> A;   int main() {     scanf( %d %d %d , &N, &M, &Q);     A.resize(N);     for (int i = 0; i < N; i++) {       long long x;       scanf( %lld , &x);       A[i] = x % 2;     }     seg_tree tree(N);     tree.build(A);     for (int q = 0; q < Q; q++) {       int type, L, R;       scanf( %d %d %d , &type, &L, &R);       L--;       if (type == 1) {         long long d;         scanf( %lld , &d);         if (d % 2 == 1) tree.update(L, R, segment_change(true));       } else if (type == 2) {         puts(tree.query(L, R).through[M] != 0 ?  1  :  2 );       }     }   }