#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
int n, m, P, Q;
int value[N];
template <typename T>
inline void chkmax(T &x, T y) {
  x = max(x, y);
}
template <typename T>
inline void chkmin(T &x, T y) {
  x = min(x, y);
}
template <typename T>
inline void read(T &x) {
  T f = 1;
  x = 0;
  char c = getchar();
  for (; !isdigit(c); c = getchar())
    if (c == '-') f = -f;
  for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
  x *= f;
}
struct info {
  int val, size;
};
struct node {
  int n;
  info p[11];
  node() { n = 0; }
  info &operator[](int x) { return p[x]; }
};
inline bool cmp(info a, info b) { return a.size > b.size; }
node operator+(node a, node b) {
  node ans = a;
  for (int i = 1; i <= b.n; ++i) {
    int flag = 1;
    for (int j = 1; j <= ans.n; ++j)
      if (ans[j].val == b[i].val) flag = 0, ans[j].size += b[i].size;
    if (flag) ans[++ans.n] = b[i];
  }
  sort(ans.p + 1, ans.p + ans.n + 1, cmp);
  if (ans.n >= Q) {
    for (int i = ans.n; i >= Q; --i)
      for (int j = 1; j <= i; ++j) ans[j].size -= ans[i].size;
    while (ans.n && ans[ans.n].size <= 0) --ans.n;
  }
  return ans;
}
struct Segment_Tree {
  int tag[N * 4];
  node a[N * 4];
  inline void build(int now, int l, int r) {
    if (l == r) {
      a[now].n = 1;
      a[now][1] = (info){value[l], 1};
      return;
    }
    int mid = l + r >> 1;
    build(now << 1, l, mid);
    build(now << 1 | 1, mid + 1, r);
    a[now] = a[now << 1] + a[now << 1 | 1];
  }
  inline void pushdown(int now, int l, int r) {
    int mid = l + r >> 1;
    if (tag[now]) {
      a[now << 1].n = 1;
      a[now << 1][1] = (info){tag[now], mid - l + 1};
      a[now << 1 | 1].n = 1;
      a[now << 1 | 1][1] = (info){tag[now], r - mid};
      tag[now << 1] = tag[now << 1 | 1] = tag[now];
      tag[now] = 0;
    }
    return;
  }
  inline void modify(int now, int l, int r, int ql, int qr, int x) {
    if (l == ql && r == qr) {
      a[now].n = 1;
      a[now][1] = (info){x, qr - ql + 1};
      tag[now] = x;
      return;
    }
    if (tag[now]) pushdown(now, l, r);
    int mid = l + r >> 1;
    if (mid >= qr)
      modify(now << 1, l, mid, ql, qr, x);
    else if (mid + 1 <= ql)
      modify(now << 1 | 1, mid + 1, r, ql, qr, x);
    else {
      modify(now << 1, l, mid, ql, mid, x);
      modify(now << 1 | 1, mid + 1, r, mid + 1, qr, x);
    }
    a[now] = a[now << 1] + a[now << 1 | 1];
  }
  inline node query(int now, int l, int r, int ql, int qr) {
    if (l == ql && r == qr) return a[now];
    int mid = l + r >> 1;
    if (tag[now]) pushdown(now, l, r);
    if (mid >= qr)
      return query(now << 1, l, mid, ql, qr);
    else if (mid + 1 <= ql)
      return query(now << 1 | 1, mid + 1, r, ql, qr);
    else
      return query(now << 1, l, mid, ql, mid) +
             query(now << 1 | 1, mid + 1, r, mid + 1, qr);
  }
} T;
int main() {
  read(n);
  read(m);
  read(P);
  Q = 100 / P + 1;
  for (int i = 1; i <= n; ++i) read(value[i]);
  T.build(1, 1, n);
  while (m--) {
    int type;
    read(type);
    if (type == 1) {
      int l, r, k;
      read(l), read(r), read(k);
      T.modify(1, 1, n, l, r, k);
    } else {
      int l, r;
      read(l), read(r);
      node ans = T.query(1, 1, n, l, r);
      printf("%d ", ans.n);
      for (int i = 1; i <= ans.n; ++i) printf("%d ", ans[i].val);
      printf("\n");
    }
  }
  return 0;
}
