#include <bits/stdc++.h>
using namespace std;
// 2024 OneWan
long long qpow(long long a, long long b, long long mod) {
long long res = 1;
while (b) {
if (b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
template<class K, class V>
struct ODT {
map<K, V> odt;
ODT(K mx) {
odt[mx + 1] = V();
}
void split(K x) {
auto it = prev(odt.upper_bound(x));
odt[x] = it -> second;
}
void assign(K L, K R, V val) { // 区间赋值
R++;
split(L); split(R);
auto it = odt.find(L);
while (it -> first != R) {
it = odt.erase(it);
}
odt[L] = val;
}
void add(K L, K R, V val) { // 区间加
R++;
split(L); split(R);
auto it = odt.find(L);
while (it -> first != R) {
K l = it -> first; // 区间左端点
K r = next(it) -> first - 1; // 区间右端点
V &v = it -> second; // 区间值
v += val;
it = next(it);
}
}
V kth(K L, K R, K rk) { // 区间第k大
R++;
split(L); split(R);
auto it = odt.find(L);
vector<pair<V, K>> res;
while (it -> first != R) {
K l = it -> first; // 区间左端点
K r = next(it) -> first - 1; // 区间右端点
V v = it -> second; // 区间值
res.push_back({v, r - l + 1});
it = next(it);
}
sort(begin(res), end(res));
for (auto &[x, y] : res) {
rk -= y;
if (rk <= 0) return x;
}
return -1;
}
V query(K L, K R, V x, V mod) { // 区间更新
R++;
split(L); split(R);
auto it = odt.find(L);
V res = 0;
while (it -> first != R) {
K l = it -> first; // 区间左端点
K r = next(it) -> first - 1; // 区间右端点
V v = it -> second; // 区间值
res = (res + qpow(v % mod, x, mod) * (r - l + 1) % mod) % mod;
it = next(it);
}
return res;
}
V& operator[](K x) {
return odt[x];
}
}; // ODT
int seed;
int rnd() {
int res = seed;
seed = (1LL * seed * 7 + 13) % 1000000007;
return res;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n, m, vmax;
cin >> n >> m >> seed >> vmax;
ODT<int, long long> odt(n);
for (int i = 1 ; i <= n ; i++) {
int a = rnd() % vmax + 1;
odt[i] = a;
}
for (int i = 1 ; i <= m ; i++) {
int op, L, R, x, y;
op = rnd() % 4 + 1;
L = rnd() % n + 1;
R = rnd() % n + 1;
if (L > R) swap(L, R);
if (op == 3) {
x = rnd() % (R - L + 1) + 1;
} else {
x = rnd() % vmax + 1;
}
if (op == 4) {
y = rnd() % vmax + 1;
}
if (op == 1) {
odt.add(L, R, x);
} else if (op == 2) {
odt.assign(L, R, x);
} else if (op == 3) {
cout << odt.kth(L, R, x) << "\n";
} else if (op == 4) {
cout << odt.query(L, R, x, y) << "\n";
}
}
return 0;
}