/* ID: espr1t TASK: KEYWORDS: */ #include #include #include #include #include using namespace std; FILE *in; FILE *out; const int MAX = 300003; const int MM = 10001; const int TREE = 1048576; const int MOD = 18181; int current; int n, k; int init[MAX], a[MAX]; int tree[TREE]; int q[MM][4], ans[MM]; int fact[MAX]; int fastPow(int num, int pwr) { int ret = 1; while (pwr) { if (pwr & 1) ret = (ret * num) % MOD; num = (num * num) % MOD; pwr >>= 1; } return ret; } int modDiv(int num, int div) { return (num * fastPow(div, MOD - 2)) % MOD; } int getWays(int N, int K) { int ans = fact[N]; ans = modDiv(ans, fact[K]); ans = modDiv(ans, fact[N - K]); return ans; } void update(int idx, int val) { idx += (TREE >> 1); while (idx > 0) { tree[idx] += val; idx >>= 1; } } int query(int idx1, int idx2) { if (idx1 > idx2) return 0; idx1 += (TREE >> 1), idx2 += (TREE >> 1); if (idx1 == idx2) return tree[idx1]; int ret = 0; ret += tree[idx1]; bool flag1 = !(idx1 & 1); idx1 >>= 1; ret += tree[idx2]; bool flag2 = (idx2 & 1); idx2 >>= 1; while (idx1 != idx2) { if (flag1) ret += tree[(idx1 << 1) | 1]; flag1 = !(idx1 & 1); idx1 >>= 1; if (flag2) ret += tree[(idx2 << 1) | 0]; flag2 = (idx2 & 1); idx2 >>= 1; } return ret; } int main(void) { in = stdin; out = stdout; in = fopen("groups.in", "rt"); out = fopen("groups.out", "wt"); fact[0] = 1; for (int i = 1; i < MAX; i++) fact[i] = (fact[i - 1] * i) % MOD; fscanf(in, "%d %d", &n, &k); for (int i = 0; i < n; i++) fscanf(in, "%d", &init[i]); for (int i = 0; i < k; i++) { fscanf(in, "%d %d %d %d", &q[i][0], &q[i][1], &q[i][2], &q[i][3]); q[i][1]--, q[i][2]--; } for (current = 0; current < 64; current++) { memcpy(a, init, sizeof(a)); memset(tree, 0, sizeof(tree)); for (int i = 0; i < n; i++) { if (a[i] == current) tree[(TREE >> 1) + i] = 1; } for (int i = (TREE >> 1) - 1; i > 0; i--) { tree[i] = tree[(i << 1) | 0] + tree[(i << 1) | 1]; } for (int i = 0; i < k; i++) { if (q[i][0] == 1) { for (int c = q[i][1]; c <= q[i][2]; c++) { if (a[c] == current) update(c, -1); a[c] = ((a[c] ^ (q[i][3] + c + 1)) & 63); if (a[c] == current) update(c, +1); } } else { int cur = query(q[i][1], q[i][2]); if (cur >= q[i][3]) { ans[i] += getWays(cur, q[i][3]); if (ans[i] >= MOD) ans[i] -= MOD; } } } } for (int i = 0; i < k; i++) { if (q[i][0] == 2) { fprintf(out, "%d\n", ans[i]); } } return 0; }