#include <bits/stdc++.h>
const int MAXN = 1.5e5 + 10;
int n, m, p;
int a[MAXN];
struct Node {
  int tot, num[5], cnt[5];
  inline friend Node operator+(Node a, Node b) {
    Node res = a;
    for (int i = 0; i < b.tot; ++i) {
      int flg = 0;
      for (int j = 0; j < res.tot; ++j)
        if (b.num[i] == res.num[j]) {
          res.cnt[j] += b.cnt[i], flg = 1;
          break;
        }
      if (flg) continue;
      if (res.tot < p) {
        res.num[res.tot] = b.num[i], res.cnt[res.tot++] = b.cnt[i];
        continue;
      }
      int num = 0;
      for (int j = 1; j < res.tot; ++j) res.cnt[j] < res.cnt[num] && (num = j);
      if (res.cnt[num] > b.cnt[i]) {
        for (int j = 0; j < res.tot; ++j) res.cnt[j] -= b.cnt[i];
      } else {
        int tmp = res.cnt[num];
        res.num[num] = b.num[i], res.cnt[num] = b.cnt[i];
        for (int j = 0; j < res.tot; ++j) res.cnt[j] -= tmp;
      }
    }
    return res;
  }
};
template <int N>
struct SegmentTree {
  static const int M = N << 2;
  Node t[M];
  int tag[M];
  inline void gai(int x, int L, int R, int val) {
    t[x].tot = 1, t[x].num[0] = tag[x] = val, t[x].cnt[0] = R - L + 1;
  }
  inline void pushUp(int x) { t[x] = t[((x) << 1)] + t[((x) << 1 | 1)]; }
  inline void pushDown(int x, int L, int R) {
    if (tag[x]) {
      int mid = (L + R) >> 1;
      gai(((x) << 1), L, mid, tag[x]), gai(((x) << 1 | 1), mid + 1, R, tag[x]),
          tag[x] = 0;
    }
  }
  void build(int x, int L, int R) {
    if (L == R) {
      t[x].tot = 1, t[x].num[0] = a[L], t[x].cnt[0] = 1;
      return;
    }
    int mid = (L + R) >> 1;
    build(((x) << 1), L, mid), build(((x) << 1 | 1), mid + 1, R), pushUp(x);
  }
  void update(int x, int L, int R, int ql, int qr, int val) {
    if (ql <= L && R <= qr) return gai(x, L, R, val);
    int mid = (L + R) >> 1;
    pushDown(x, L, R);
    if (ql <= mid) update(((x) << 1), L, mid, ql, qr, val);
    if (qr > mid) update(((x) << 1 | 1), mid + 1, R, ql, qr, val);
    pushUp(x);
  }
  Node query(int x, int L, int R, int ql, int qr) {
    if (ql <= L && R <= qr) return t[x];
    int mid = (L + R) >> 1;
    pushDown(x, L, R);
    if (qr <= mid)
      return query(((x) << 1), L, mid, ql, qr);
    else if (ql > mid)
      return query(((x) << 1 | 1), mid + 1, R, ql, qr);
    else
      return query(((x) << 1), L, mid, ql, qr) +
             query(((x) << 1 | 1), mid + 1, R, ql, qr);
  }
};
SegmentTree<MAXN> Tr;
int main() {
  scanf("%d%d%d", &n, &m, &p), p = 100 / p;
  for (int i = 1; i <= n; ++i) scanf("%d", a + i);
  Tr.build(1, 1, n);
  for (int i = 1, opt, L, R, val; i <= m; ++i) {
    scanf("%d%d%d", &opt, &L, &R);
    if (opt == 1)
      scanf("%d", &val), Tr.update(1, 1, n, L, R, val);
    else {
      Node ans = Tr.query(1, 1, n, L, R);
      printf("%d", ans.tot);
      for (int j = 0; j < ans.tot; ++j) printf(" %d", ans.num[j]);
      puts("");
    }
  }
  return 0;
}
