#include <vector>
#include <algorithm>
namespace nachia {
template<class Elem>
struct assign_segment_tree {
private:
int N;
int logN;
std::vector<int> lazy;
std::vector<int> nodeRank;
std::vector<Elem> lazyTable;
std::vector<Elem> prod;
int tableIterator;
int bitReverse(int x){
int y = 0;
for(int i=0; i<logN; i++){
y = (y << 1) | (x & 1);
x >>= 1;
}
return y;
}
void apply(int p, int k){
if(p < N) lazy[p] = k;
prod[p] = lazyTable[(k+N*2-nodeRank[p]) & (N*2-1)];
}
void propagate(int p){
if(p >= N || lazy[p] == -1) return;
apply(p*2, lazy[p]);
apply(p*2+1, lazy[p]);
lazy[p] = -1;
}
void propagateFor(int p){
p += N;
for(int d=logN; d>=1; d--) propagate(p>>d);
}
void rangeUpdateRecursion(int l, int r, int k, int i, int a, int b){
if(b <= l || r <= a) return;
if(l <= a && b <= r){ apply(i, k); return; }
propagate(i);
rangeUpdateRecursion(l, r, k, i*2, a, (a+b)/2);
rangeUpdateRecursion(l, r, k, i*2+1, (a+b)/2, b);
prod[i] = prod[i*2] * prod[i*2+1];
}
Elem rangeProductRecursion(int l, int r, int i, int a, int b){
if(l <= a && b <= r) return prod[i];
propagate(i);
if(r <= (a+b)/2) return rangeProductRecursion(l, r, i*2, a, (a+b)/2);
if((a+b)/2 <= l) return rangeProductRecursion(l, r, i*2+1, (a+b)/2, b);
Elem lq = rangeProductRecursion(l, r, i*2, a, (a+b)/2);
Elem rq = rangeProductRecursion(l, r, i*2+1, (a+b)/2, b);
return lq * rq;
}
public:
assign_segment_tree(int n, Elem filler){
N = 1; logN = 0; while(N < n){ N *= 2; logN++; }
tableIterator = 0;
lazy.assign(N, -1);
nodeRank.assign(N*2, N);
for(int i=N-1; i>=1; i--) nodeRank[i] = nodeRank[i*2] >> 1;
lazyTable.assign(N*2, filler);
prod.assign(N*2, filler);
for(int i=N-1; i>=1; i--) prod[i] = prod[i*2] * prod[i*2+1];
}
void assign(int l, int r, Elem x){
int k = tableIterator++;
if(tableIterator == N*2) tableIterator = 0;
lazyTable[(k+N*2-N) & (N*2-1)] = x;
for(int i=1; i<=logN; i++){
x = x * x;
lazyTable[(k+N*2-(N>>i)) & (N*2-1)] = x;
}
rangeUpdateRecursion(l, r, k, 1, 0, N);
propagateFor(bitReverse(k&(N-1)));
}
// l < r
Elem fold(int l, int r){
return rangeProductRecursion(l, r, 1, 0, N);
}
};
}
#include <atcoder/modint>
using Modint = atcoder::static_modint<998244353>;
namespace noshi91 {
using T = Modint;
T op(T l, T r) { return l * r; }
T id() { return 1; }
class assign_segment_tree {
private:
class node {
public:
T sum;
T *lazy;
node() : sum(id()), lazy(nullptr) {}
T get() {
if (lazy) {
return *lazy;
} else {
return sum;
}
}
};
int height;
std::vector<node> tree;
std::vector<T> table;
void push(int index) {
if (tree[index].lazy) {
tree[index * 2].lazy = tree[index].lazy - 1;
tree[index * 2 + 1].lazy = tree[index].lazy - 1;
tree[index].sum = *tree[index].lazy;
tree[index].lazy = nullptr;
}
}
T fold(int index, int n_left, int n_right, int q_left, int q_right) {
if (q_left <= n_left && n_right <= q_right) {
return tree[index].get();
}
if (n_right <= q_left || q_right <= n_left) {
return id();
}
push(index);
int n_mid = (n_left + n_right) / 2;
return op(fold(index * 2, n_left, n_mid, q_left, q_right),
fold(index * 2 + 1, n_mid, n_right, q_left, q_right));
}
void assign(int index, int n_left, int n_right, int q_left, int q_right,
T *lazy) {
if (q_left <= n_left && n_right <= q_right) {
tree[index].lazy = lazy;
return;
}
if (n_right <= q_left || q_right <= n_left) {
return;
}
push(index);
int n_mid = (n_left + n_right) / 2;
assign(index * 2, n_left, n_mid, q_left, q_right, lazy - 1);
assign(index * 2 + 1, n_mid, n_right, q_left, q_right, lazy - 1);
tree[index].sum = op(tree[index * 2].get(), tree[index * 2 + 1].get());
}
public:
assign_segment_tree(int n) {
height = 1;
int s = 1;
while (s < n) {
s *= 2;
++height;
}
tree.assign(s * 2, node());
table.reserve(s * 2);
}
int size() { return tree.size() / 2; }
T fold(int first, int last) { return fold(1, 0, size(), first, last); }
void assign(int first, int last, T value) {
for (int i = 0; i < height; ++i) {
table.push_back(value);
value = op(value, value);
}
assign(1, 0, size(), first, last, &table.back());
if (table.capacity() - table.size() < height) {
for (int i = 1; i < size(); ++i) {
push(i);
}
for (int i = size(); i != tree.size(); ++i) {
if (tree[i].lazy) {
tree[i].sum = *tree[i].lazy;
tree[i].lazy = nullptr;
}
}
table.clear();
}
}
};
}
struct Problem {
int N;
int Q;
Modint init;
std::vector<int> T;
std::vector<int> L;
std::vector<int> R;
std::vector<Modint> val;
};
#include <unordered_map>
#include <cassert>
#include <cstdint>
namespace nachia{
class Xoshiro256pp{
public:
using i32 = int32_t;
using u32 = uint32_t;
using i64 = int64_t;
using u64 = uint64_t;
private:
uint64_t s[4];
// https://prng.di.unimi.it/xoshiro256plusplus.c
static inline uint64_t rotl(const uint64_t x, int k) noexcept {
return (x << k) | (x >> (64 - k));
}
inline uint64_t gen(void) noexcept {
const uint64_t result = rotl(s[0] + s[3], 23) + s[0];
const uint64_t t = s[1] << 17;
s[2] ^= s[0];
s[3] ^= s[1];
s[1] ^= s[2];
s[0] ^= s[3];
s[2] ^= t;
s[3] = rotl(s[3], 45);
return result;
}
// https://xoshiro.di.unimi.it/splitmix64.c
u64 splitmix64(u64& x) {
u64 z = (x += 0x9e3779b97f4a7c15);
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
return z ^ (z >> 31);
}
public:
void seed(u64 x = 7001){
assert(x != 0);
s[0] = x;
for(int i=1; i<4; i++) s[i] = splitmix64(x);
}
Xoshiro256pp(){ seed(); }
u64 rng64() { return gen(); }
u64 operator()(){ return gen(); }
// generate x : l <= x <= r
u64 random_unsigned(u64 l,u64 r){
assert(l<=r);
r-=l;
auto res = rng64();
if(res<=r) return res+l;
u64 d = r+1;
u64 max_valid = 0xffffffffffffffff/d*d;
while(true){
auto res = rng64();
if(res<=max_valid) break;
}
return res%d+l;
}
// generate x : l <= x <= r
i64 random_signed(i64 l,i64 r){
assert(l<=r);
u64 unsigned_l = (u64)l ^ (1ull<<63);
u64 unsigned_r = (u64)r ^ (1ull<<63);
u64 unsigned_res = random_unsigned(unsigned_l,unsigned_r) ^ (1ull<<63);
return (i64)unsigned_res;
}
// permute x : n_left <= x <= n_right
// output r from the front
template<class Int>
std::vector<Int> random_nPr(Int n_left, Int n_right, Int r){
Int n = n_right-n_left;
assert(n>=0);
assert(r<=(1ll<<27));
if(r==0) return {};
assert(n>=r-1);
std::vector<Int> V;
std::unordered_map<Int,Int> G;
for(int i=0; i<r; i++){
Int p = random_signed(i,n);
Int x = p - G[p];
V.push_back(x);
G[p] = p - (i - G[i]);
}
for(Int& v : V) v+=n_left;
return V;
}
// V[i] := V[perm[i]]
// using swap
template<class E,class PermInt_t>
void permute_inplace(std::vector<E>& V,std::vector<PermInt_t> perm){
assert(V.size() == perm.size());
int N=V.size();
for(int i=0; i<N; i++){
int p=i;
while(perm[p]!=i){
assert(0 <= perm[p] && perm[p] < N);
assert(perm[p] != perm[perm[p]]);
std::swap(V[p],V[perm[p]]);
int pbuf = perm[p]; perm[p] = p; p = pbuf;
}
perm[p] = p;
}
}
template<class E>
std::vector<E> shuffle(const std::vector<E>& V){
int N=V.size();
auto P = random_nPr(0,N-1,N);
std::vector<E> res;
res.reserve(N);
for(int i=0; i<N; i++) res.push_back(V[P[i]]);
return res;
}
// shuffle using swap
template<class E>
void shuffle_inplace(std::vector<E>& V){
int N=V.size();
permute_inplace(V,random_nPr(0,N-1,N));
}
};
} // namespace nachia
nachia::Xoshiro256pp rng;
Problem generate(int n, int q){
Problem res;
res.N = n;
res.Q = q;
res.init = 1;
for(int i=0; i<q; i++){
int l = 0, r = 0;
while(l == r){
l = rng.random_signed(0, n);
r = rng.random_signed(0, n);
if(l > r) std::swap(l, r);
}
res.T.push_back(rng.random_signed(0, 1));
res.L.push_back(l);
res.R.push_back(r);
res.val.push_back(rng.random_signed(1, 992844352));
}
return res;
}
std::vector<int> solve_nachia(Problem problem){
std::vector<int> ans;
nachia::assign_segment_tree<Modint> A(problem.N, problem.init);
for(int qi=0; qi<problem.Q; qi++){
int t = problem.T[qi];
int l = problem.L[qi];
int r = problem.R[qi];
Modint e = problem.val[qi];
if(t == 0){
A.assign(l, r, e);
} else {
ans.push_back((int)A.fold(l, r).val());
}
}
return ans;
}
std::vector<int> solve_noshi91(Problem problem){
std::vector<int> ans;
noshi91::assign_segment_tree A(problem.N);
for(int qi=0; qi<problem.Q; qi++){
int t = problem.T[qi];
int l = problem.L[qi];
int r = problem.R[qi];
Modint e = problem.val[qi];
if(t == 0){
A.assign(l, r, e);
} else {
ans.push_back((int)A.fold(l, r).val());
}
}
return ans;
}
#include <iostream>
#include <chrono>
int main(){
std::ios::sync_with_stdio(false); std::cin.tie(nullptr);
unsigned long long seed; std::cin >> seed;
int nq; std::cin >> nq;
// case 1 : seed = 144262995209904656
// case 2 : seed = 7577536898627496
// case 3 : seed = 795742045562236292
rng.seed(seed);
auto problem = generate(nq, nq);
auto t0 = std::chrono::high_resolution_clock::now();
auto ans = solve_nachia(std::move(problem));
// auto ans = solve_noshi91(std::move(problem));
auto t1 = std::chrono::high_resolution_clock::now();
std::cout << "T = " << (t1-t0).count() << std::endl;
for(auto a : ans) std::cout << a << '\n';
return 0;
}