#include <bits/stdc++.h>
using namespace std;
const int N = 150010;
struct Data {
  pair<int, int> num[5];
  Data() { memset(num, 0, sizeof(num)); }
  Data(int a) {
    memset(num, 0, sizeof(num));
    num[0].first = a, num[0].second = 1;
  }
};
int lim;
inline Data Merge(const Data &a, const Data &b) {
  Data res = a;
  for (int i = 0; i < lim; i++)
    if (b.num[i].second) {
      bool flag = false;
      for (int j = 0; j < lim; j++)
        if (res.num[j].first == b.num[i].first) {
          res.num[j].second += b.num[i].second;
          flag = true;
          break;
        }
      if (!flag)
        for (int j = 0; j < lim; j++)
          if (!res.num[j].second) {
            res.num[j] = b.num[i];
            flag = true;
            break;
          }
      if (flag) continue;
      int mn = 1e9;
      for (int j = 0; j < lim; j++) mn = min(mn, res.num[j].second);
      if (mn >= b.num[i].second) {
        for (int j = 0; j < lim; j++) res.num[j].second -= b.num[i].second;
        continue;
      }
      flag = false;
      for (int j = 0; j < lim; j++)
        if (res.num[j].second == mn && !flag) {
          flag = true, res.num[j].first = b.num[i].first;
          res.num[j].second = b.num[i].second - mn;
        } else
          res.num[j].second -= mn;
    }
  return res;
}
struct node {
  int l, r, tag;
  Data val;
} T[N << 2];
inline void pushup(int rt) {
  T[rt].val = Merge(T[rt << 1].val, T[rt << 1 | 1].val);
}
inline void cover(int rt, int x) {
  int l = T[rt].l, r = T[rt].r;
  T[rt].val = Data(x), T[rt].val.num[0].second = r - l + 1;
}
inline void pushdown(int rt) {
  cover(rt << 1, T[rt].tag), cover(rt << 1 | 1, T[rt].tag);
  T[rt << 1].tag = T[rt].tag, T[rt << 1 | 1].tag = T[rt].tag, T[rt].tag = 0;
}
int a[N];
void build(int rt, int l, int r) {
  T[rt].l = l, T[rt].r = r;
  if (l == r) return T[rt].val = Data(a[l]), void();
  int mid = (l + r) >> 1;
  build(rt << 1, l, mid), build(rt << 1 | 1, mid + 1, r);
  pushup(rt);
}
void update(int rt, int start, int end, int x) {
  int l = T[rt].l, r = T[rt].r, mid = (l + r) >> 1;
  if (start <= l && r <= end) return cover(rt, x), T[rt].tag = x, void();
  if (T[rt].tag) pushdown(rt);
  if (start <= mid) update(rt << 1, start, end, x);
  if (end > mid) update(rt << 1 | 1, start, end, x);
  pushup(rt);
}
Data query(int rt, int start, int end) {
  int l = T[rt].l, r = T[rt].r, mid = (l + r) >> 1;
  if (start <= l && r <= end) return T[rt].val;
  if (T[rt].tag) pushdown(rt);
  if (end <= mid) return query(rt << 1, start, end);
  if (start > mid) return query(rt << 1 | 1, start, end);
  return Merge(query(rt << 1, start, end), query(rt << 1 | 1, start, end));
}
int main() {
  int n, q, p;
  scanf("%d%d%d", &n, &q, &p), lim = 100 / p;
  for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
  build(1, 1, n);
  while (q--) {
    int op, A, B, C;
    scanf("%d%d%d", &op, &A, &B);
    if (op == 1)
      scanf("%d", &C), update(1, A, B, C);
    else {
      Data res = query(1, A, B);
      printf("%d ", lim);
      for (int i = 1; i <= lim; i++) printf("%d ", res.num[i - 1].first);
      puts("");
    }
  }
}
