Problem:
I: XOR Increasing Problems
問題
\(N\) 組の整数のペア \((L_i, R_i)\ (1 \leq i \leq N)\) が与えられます。
次に、\(Q\) 個のクエリが与えられます。 \(i\) 番目のクエリではまず \(t_{i}\) が与えられるので、\(t_{i}\) に応じて以下の操作を行ってください。
\(t_{i}=1\): 整数 \(lp_{i}\) , \(rp_{i}\) , \(l_{i}\) , \(r_{i}\) が与えられる。 \(lp_i \le j \le rp_i\) を満たす \(j\) について \(L_{j}\) を \(l_{i}\) で、\(R_{j}\) を \(r_{i}\) で置き換える。
\(t_{i}=2\): 整数 \(lp_i\) , \(rp_i\) が与えられる。olphe君は次の一連の操作を行い、数列 \(a\) と整数 \(j\) のペアを作る。
長さ \(rp_{i} - lp_{i} + 1\) の数列 \(a = ({a_{1}, a_{2}, \dots, a_{rp_{i} - lp_{i} + 1}})\) を作る。ただし、\(a\) の \(k\) 番目の要素は \(L_{lp_{i} + k - 1}\) 以上 \(R_{lp_{i} + k - 1}\) 以下の整数から選ぶ \((1 \leq k \leq rp_{i} - lp_{i} + 1)\)。
ここで、長さ \(M\) の数列 \(b=(b_{1}, b_{2}, \dots, b_{M})\) のスコアを \(f(b) = \left\{ \begin{array}{ll} 0 & (M = 0) \\ b_{1}\ \mathrm{XOR}\ b_{2}\ \mathrm{XOR}\ \cdots\ \mathrm{XOR}\ b_{M} & (M \geq 1) \end{array} \right.\) と定める。
\( 1 \leq j \leq rp_{i} - lp_{i} + 1 \) を満たす整数 \(j\) を決める。ただし、数列 \(a\) の \(j\) 番目の要素を取り除いた数列を \(a'\) としたとき、\(f(a) < f(a')\) でなければならない。
olphe君が作ることができる相異なる数列 \(a\) と整数 \(j\) のペアの通り数を \(998244353\) で割ったあまりを出力する。
入力形式
N
L_{1}
R_{1}
L_{2}
R_{2}
︙
L_{N}
R_{N}
Q
query_{1}
query_{2}
︙
query_{Q}
各クエリの情報は、以下の形式で与えられる。
\(t_{i}=1\) の場合
t_{i}
lp_{i}
rp_{i}
l_{i}
r_{i}
\(t_{i}=2\) の場合
t_{i}
lp_i
rp_i
制約
\(2\leq N\leq 10000\)
\(1\leq L_{i}\leq R_{i}\leq 10^9\) \((1\leq i \leq N)\)
\(2\leq Q\leq 10000\)
\(1\leq t_i\leq 2\) \((1\leq i \leq Q)\)
\(1\leq lp_i \le rp_i\leq N\) \((1\leq i \leq Q)\)
\(1\leq l_i\leq r_i \leq 10^9\) \((1\leq i \leq Q)\)
出力形式
\(t_{i}=2\) のクエリについて、クエリが与えられた順にその答えを改行区切りで出力してください。
入力例1
3
3 4
1 2
3 4
4
1 1 1 3 4
2 1 2
1 2 2 5 6
2 1 3
出力例1
3
12
例えば \(2\) 番目のクエリの時点で作ることができる数列 \(a = (3,1,3)\) のスコアは \(1\) で、\(2\) 番目の要素を取り除いた数列である \(a' = (3,3)\) のスコアは \(0\) です。
入力例2
2
1 2
2 4
2
1 1 2 2 3
2 1 2
出力例2
8
どのように \(a\) や \(j\) を作ろうとしても条件を満たします。

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define REP(i,n) for(int i=0;i<(n);i++)
#define RREP(i,n) for(int i=(n-1);i>=0;i--)
#define ALL(v) v.begin(),v.end()

//BEGIN CUT HERE
template<typename T, T MOD = 1000000007>
struct Mint{
  inline static constexpr T mod = MOD;
  T v;
  Mint():v(0){}
  Mint(signed v):v(v){}
  Mint(long long t){v=t%MOD;if(v<0) v+=MOD;}

  Mint pow(long long k){
    Mint res(1),tmp(v);
    while(k){
      if(k&1) res*=tmp;
      tmp*=tmp;
      k>>=1;
    }
    return res;
  }

  static Mint add_identity(){return Mint(0);}
  static Mint mul_identity(){return Mint(1);}

  Mint inv(){return pow(MOD-2);}

  Mint& operator+=(Mint a){v+=a.v;if(v>=MOD)v-=MOD;return *this;}
  Mint& operator-=(Mint a){v+=MOD-a.v;if(v>=MOD)v-=MOD;return *this;}
  Mint& operator*=(Mint a){v=1LL*v*a.v%MOD;return *this;}
  Mint& operator/=(Mint a){return (*this)*=a.inv();}

  Mint operator+(Mint a) const{return Mint(v)+=a;}
  Mint operator-(Mint a) const{return Mint(v)-=a;}
  Mint operator*(Mint a) const{return Mint(v)*=a;}
  Mint operator/(Mint a) const{return Mint(v)/=a;}

  Mint operator+() const{return *this;}
  Mint operator-() const{return v?Mint(MOD-v):Mint(v);}

  bool operator==(const Mint a)const{return v==a.v;}
  bool operator!=(const Mint a)const{return v!=a.v;}

  static Mint comb(long long n,int k){
    Mint num(1),dom(1);
    for(int i=0;i<k;i++){
      num*=Mint(n-i);
      dom*=Mint(i+1);
    }
    return num/dom;
  }
};
template<typename T, T MOD>
ostream& operator<<(ostream &os,Mint<T, MOD> m){os<<m.v;return os;}
//END CUT HERE
using ll=long long;
using mint=Mint<ll,998244353>;

//BEGIN CUT HERE
template <typename T,typename E>
struct SegmentTree{
  using F = function<T(T,T)>;
  using G = function<T(T,E)>;
  using H = function<E(E,E)>;
  //この辺はとりあえずbeetのブログ読むのが良さそう？
  //最初の具体例で言うとTとEが0以上の整数で、F(a,b):max(a,b) G(a,α):if(α)a=α H(α,β):if(β)α=β のはず
  int n,height;
  F f;
  G g;
  H h;
  T ti;
  E ei;
  vector<T> dat;
  vector<E> laz;
  vector<int> leng;
  SegmentTree()=default;
  SegmentTree(F f,G g,H h,T ti,E ei):
    f(f),g(g),h(h),ti(ti),ei(ei){}
  
  
  /*
  イメージ的には
  initとbuildは初期化　buildだとvectorで初期化出来る
  reflectは作用済のdatを返すので適切なdatとlazが入っていればいい
  propagateはkの作用をeiにリセットする役割で、作用を全部済ませる（datの更新と子のlazへの渡し）
  thrustは（vectorでの）kを渡すとkの列を上から順にpropagateすることで上のlazを空にする
  recalcは（vectorでの）kを渡すとkの列を下から順にdatを子のdatのクエリ済のものに更新する（自分のlazは適用しない）
  updateは（vectorでの）a,b,xを渡すと[a,b)に作用xを適用
  　　　　　まず閉区間で区間の端二列に関してはlazを一回空にしておく
  　　　　　区間をカバーする最小個のブロックのlazを更新する
          そのあと閉区間で端っこに関してはdatを変更していく
  set_valは要素一つに値一つを代入する
  　　　　　その列のlazを空にしてから一番下に代入して、上にどんどんdatを更新
  queryは普通にやるだけなんだけど、なんでこれで良いかを考える必要がありそう
  一番引っかかったのはqueryやupdateで両端だけthrustやrecalcをするか
  例えば[a,b]にupdateやったあとに[c,d]に対してqueryをする時に[c,d]で見るノードは
  1.[a,b]でアプデしたノード
  2.[a,b]に関係ないノード
  3.a,b,c,dいずれかの上にあるノード
  だけってのが成り立つからっぽい気がする
  */

  void init(int n_){
    n=1;height=0;
    while(n<n_) n<<=1,height++;
    dat.assign(2*n,ti);
    laz.assign(2*n,ei);
    leng.resize(2*n);
    int tmp=n;
    for(int j=1;j<2*n;j*=2){
      for(int i=j;i<2*j;i++)leng[i]=tmp;
      tmp/=2;
    }
  }

  void build(const vector<T> &v){
    int n_=v.size();
    init(n_);
    for(int i=0;i<n_;i++) dat[n+i]=v[i];
    for(int i=n-1;i;i--)
      dat[i]=f(dat[(i<<1)|0],dat[(i<<1)|1]);
  }
  
  //inlineは実行時間が短くなる魔法なので読む時には気にしなくていいはず

  inline T reflect(int k){
    return laz[k]==ei?dat[k]:g(dat[k],laz[k]);//作用済のdat[k]の値を返す
  }
  
  //propagateは伝わるって意味らしい
  inline void propagate(int k){//laz[k]をdat[k]と子のlazに適用して自身をeiに戻す
    if(laz[k]==ei) return;
    laz[(k<<1)|0]=h(laz[(k<<1)|0],laz[k]);
    laz[(k<<1)|1]=h(laz[(k<<1)|1],laz[k]);//子の作用の更新
    dat[k]=reflect(k);//dat[k]を作用済に変更
    laz[k]=ei;//作用したのでlaz[k]はリセット
  }

  //thrustは突き出すって意味らしい
  inline void thrust(int k){
    for(int i=height;i;i--) propagate(k>>i);//kの列を一番上から更新させていく 子がいない一番下にはやらない
  }

  inline void recalc(int k){
    while(k>>=1)
      dat[k]=f(reflect((k<<1)|0),reflect((k<<1)|1));//kの列を下から上に更新していく
  }

  void update(int a,int b,E x){//[a,b)に作用Eを適用
    thrust(a+=n);//aを一番下のそれにして、その列の一番上から現在溜まっている作用を済ませておく
    thrust(b+=n-1);//bについても同様　ただしここでbは閉区間としてのそれになっている
    for(int l=a,r=b+1;l<r;l>>=1,r>>=1){//[a,b)の範囲を一番カバーできるlaz(だいたいlog個)を更新する
      if(l&1) laz[l]=h(laz[l],x),l++;
      if(r&1) --r,laz[r]=h(laz[r],x);
    }
    recalc(a);//今回作用を施した端っこについて下から上にdatを更新していく
    recalc(b);
  }

  void set_val(int a,T x){//aにxを代入
    thrust(a+=n);//aを一番下のそれにして、その列の一番上から現在溜まっている作用を済ませておく
    dat[a]=x;laz[a]=ei;//aの値をxに変更してそこのlazをリセット
    recalc(a);//aの上のdatを更新
  }

  T query(int a,int b){//[a,b)のfを求めるいつものクエリ
    thrust(a+=n);//aを一番下のそれにして、その列の一番上から現在溜まっている作用を済ませておく
    thrust(b+=n-1);//bを一番下のそれにして、その列の一番上から現在溜まっている作用を済ませておく
    T vl=ti,vr=ti;
    for(int l=a,r=b+1;l<r;l>>=1,r>>=1) {
      if(l&1) vl=f(vl,reflect(l++));
      if(r&1) vr=f(reflect(--r),vr);
    }
    return f(vl,vr);
  }

  template<typename C>
  int find(int st,C &check,T &acc,int k,int l,int r){
    if(l+1==r){
      acc=f(acc,reflect(k));
      return check(acc)?k-n:-1;
    }
    propagate(k);
    int m=(l+r)>>1;
    if(m<=st) return find(st,check,acc,(k<<1)|1,m,r);
    if(st<=l&&!check(f(acc,dat[k]))){
      acc=f(acc,dat[k]);
      return -1;
    }
    int vl=find(st,check,acc,(k<<1)|0,l,m);
    if(~vl) return vl;
    return find(st,check,acc,(k<<1)|1,m,r);
  }

  template<typename C>
  int find(int st,C &check){
    T acc=ti;
    return find(st,check,acc,1,0,n);
  }
};
//END CUT HERE

struct P{
  mint odd,even;
  bool operator==(const P &x){
    return odd==x.odd&&even==x.even;
  }
};
auto prod=[](P a,P b)->P{
  return {a.odd*b.even+a.even*b.odd,a.odd*b.odd+a.even*b.even};
};
auto sum=[](P a,P b)->P{//sumと言うか和
  return {a.odd+b.odd,a.even+b.even};
};

bool in(int S,int a){
  return (S>>a)&1;
}

mint stand(int A,int b){//[0,A]でb bitが立ってるものの個数
  mint res=0;
  for(int k=29;k>b;k--)if(in(A,k))res+=mint(2).pow(k-1);
  if(in(A,b))res+=1+(((1<<b)-1)&A);
  return res;
}
P num(int L,int R,int b){
  mint on=stand(R,b)-stand(L-1,b);
  return {on,mint(R-L+1)-on};
}

mint mxstand (int A,int b){//[0,A]でb bitが最上位bitであるものの個数
  if(A<(1<<b))return 0;
  if(A>=(1<<(b+1)))return mint(2).pow(b);
  return A-(1<<b)+1;
}
P mxnum(int L,int R,int b){
  return {mxstand(R,b)-mxstand(L-1,b),0};
}

struct T{
  P f,g;
  int l;
};
auto prod_t=[](T a,T b)->T{
  return {prod(a.f,b.f),sum(prod(a.f,b.g),prod(a.g,b.f)),a.l+b.l};
};
struct E{
  P num,mxnum;
  bool operator==(const E &x){
    return num==x.num&&mxnum==x.mxnum;
  }
};
const E ei={-1,-1};
auto mrge=[](E a,E b)->E{
  if(b==ei)return a;
  return b;
};
auto aply=[](T a,E b)->T{
  int N=a.l;
  a.f={0,1};
  P cpy=b.num;
  while(N){
    if(N&1)a.f=prod(a.f,cpy);
    cpy=prod(cpy,cpy);
    N>>=1;
  }
  N=a.l-1;
  a.g={0,1};
  cpy=b.num;
  while(N){
    if(N&1)a.g=prod(a.g,cpy);
    cpy=prod(cpy,cpy);
    N>>=1;
  }
  swap(a.g.odd,a.g.even);
  a.g.odd*=b.mxnum.odd*a.l;
  a.g.even*=b.mxnum.odd*a.l;
  return a;
};
vector<SegmentTree<T,E>> seg(30);

int main(){
  //REP(j,5)cout<<num(3,4,j).even<<" "<<num(3,4,j).odd
  //<<" "<<mxnum(3,4,j).even<<" "<<mxnum(3,4,j).even<<endl;
  int n;cin>>n;
  REP(j,30){
    seg[j]=SegmentTree<T,E>(prod_t,aply,mrge,{1,0,0},ei);
    seg[j].init(n+5);
  }
  REP(i,n){
    int l,r;cin>>l>>r;
    REP(j,30)seg[j].set_val(i,{num(l,r,j),mxnum(l,r,j),1});
  }
  int q;cin>>q;
  REP(_,q){
    int t;cin>>t;
    if(t==1){
      int lp,rp,l,r;cin>>lp>>rp>>l>>r;lp--;
      REP(j,30)seg[j].update(lp,rp,{num(l,r,j),mxnum(l,r,j)});
    }
    else{
      int lp,rp;cin>>lp>>rp;lp--;
      mint ans=0;
      //REP(j,5)cout<<seg[j].query(lp,rp).g.even<<" ";cout<<endl;
      REP(j,30)ans+=seg[j].query(lp,rp).g.even;
      cout<<ans<<endl;
    }
  }
}
accuracy: 1
time_ms: 1640
memory_kb: 76484
final_rank: 16

code_snippet: #pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb(...) emplace_back(__VA_ARGS__)
#define mp(a, b) make_pair(a, b)
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define lscan(x) scanf("%I64d", &x)
#define lprint(x) printf("%I64d", x)
#define rep(i, n) for (ll i = 0; i < (n); i++)
#define rep2(i, n) for (ll i = (ll)n - 1; i >= 0; i--)
#define REP(i, l, r) for (ll i = l; i < (r); i++)
#define REP2(i, l, r) for (ll i = (ll)r - 1; i >= (l); i--)
#define siz(x) (ll) x.size()
template <class T>
using rque = priority_queue<T, vector<T>, greater<T>>;

template <class T>
bool chmin(T &a, const T &b) {
    if (b < a) {
        a = b;
        return 1;
    }
    return 0;
}

template <class T>
bool chmax(T &a, const T &b) {
    if (b > a) {
        a = b;
        return 1;
    }
    return 0;
}

ll gcd(ll a, ll b) {
    if (a == 0)
        return b;
    if (b == 0)
        return a;
    ll cnt = a % b;
    while (cnt != 0) {
        a = b;
        b = cnt;
        cnt = a % b;
    }
    return b;
}

long long extGCD(long long a, long long b, long long &x, long long &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    long long d = extGCD(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

struct UnionFind {
    vector<ll> data;
    int num;

    UnionFind(int sz) {
        data.assign(sz, -1);
        num = sz;
    }

    bool unite(int x, int y) {
        x = find(x), y = find(y);
        if (x == y)
            return (false);
        if (data[x] > data[y])
            swap(x, y);
        data[x] += data[y];
        data[y] = x;
        num--;
        return (true);
    }

    int find(int k) {
        if (data[k] < 0)
            return (k);
        return (data[k] = find(data[k]));
    }

    ll size(int k) { return (-data[find(k)]); }

    bool same(int x, int y) { return find(x) == find(y); }
};

template <int mod>
struct ModInt {
    int x;

    ModInt() : x(0) {}

    ModInt(int64_t y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {}

    ModInt &operator+=(const ModInt &p) {
        if ((x += p.x) >= mod)
            x -= mod;
        return *this;
    }

    ModInt &operator-=(const ModInt &p) {
        if ((x += mod - p.x) >= mod)
            x -= mod;
        return *this;
    }

    ModInt &operator*=(const ModInt &p) {
        x = (int)(1LL * x * p.x % mod);
        return *this;
    }

    ModInt &operator/=(const ModInt &p) {
        *this *= p.inverse();
        return *this;
    }

    ModInt operator-() const { return ModInt(-x); }

    ModInt operator+(const ModInt &p) const { return ModInt(*this) += p; }

    ModInt operator-(const ModInt &p) const { return ModInt(*this) -= p; }

    ModInt operator*(const ModInt &p) const { return ModInt(*this) *= p; }

    ModInt operator/(const ModInt &p) const { return ModInt(*this) /= p; }

    bool operator==(const ModInt &p) const { return x == p.x; }

    bool operator!=(const ModInt &p) const { return x != p.x; }

    ModInt inverse() const {
        int a = x, b = mod, u = 1, v = 0, t;
        while (b > 0) {
            t = a / b;
            swap(a -= t * b, b);
            swap(u -= t * v, v);
        }
        return ModInt(u);
    }

    ModInt pow(int64_t n) const {
        ModInt ret(1), mul(x);
        while (n > 0) {
            if (n & 1)
                ret *= mul;
            mul *= mul;
            n >>= 1;
        }
        return ret;
    }

    friend ostream &operator<<(ostream &os, const ModInt &p) { return os << p.x; }

    friend istream &operator>>(istream &is, ModInt &a) {
        int64_t t;
        is >> t;
        a = ModInt<mod>(t);
        return (is);
    }

    static int get_mod() { return mod; }
};

ll mpow2(ll x, ll n, ll mod) {
    ll ans = 1;
    while (n != 0) {
        if (n & 1)
            ans = ans * x % mod;
        x = x * x % mod;
        n = n >> 1;
    }
    return ans;
}
/*
ll modinv2(ll a, ll mod) {
    ll b = mod, u = 1, v = 0;
    while (b) {
        ll t = a / b;
        a -= t * b;
        swap(a, b);
        u -= t * v;
        swap(u, v);
    }
    u %= mod;
    if (u < 0) u += mod;
    return u;
}
*/

// constexpr int mod = 1000000007;
constexpr int mod = 998244353;
// constexpr int mod = 31607;
using mint = ModInt<mod>;

mint mpow(mint x, ll n) {
    mint ans = 1;
    while (n != 0) {
        if (n & 1)
            ans *= x;
        x *= x;
        n = n >> 1;
    }
    return ans;
}

// ----- library -------
template <typename Monoid, typename OperatorMonoid = Monoid>
struct LazySegmentTree {
    using F = function<Monoid(Monoid, Monoid)>;
    using G = function<Monoid(Monoid, OperatorMonoid)>;
    using H = function<OperatorMonoid(OperatorMonoid, OperatorMonoid)>;

    int sz, height;
    vector<Monoid> data;
    vector<OperatorMonoid> lazy;
    const F f;
    const G g;
    const H h;
    const Monoid M1;
    const OperatorMonoid OM0;

    LazySegmentTree(int n, const F f, const G g, const H h, const Monoid &M1, const OperatorMonoid OM0) : f(f), g(g), h(h), M1(M1), OM0(OM0) {
        sz = 1;
        height = 0;
        while (sz < n) sz <<= 1, height++;
        data.assign(2 * sz, M1);
        lazy.assign(2 * sz, OM0);
    }

    void set(int k, const Monoid &x) { data[k + sz] = x; }

    void build() {
        for (int k = sz - 1; k > 0; k--) { data[k] = f(data[2 * k + 0], data[2 * k + 1]); }
    }

    inline void propagate(int k) {
        if (lazy[k] != OM0) {
            lazy[2 * k + 0] = h(lazy[2 * k + 0], lazy[k]);
            lazy[2 * k + 1] = h(lazy[2 * k + 1], lazy[k]);
            data[k] = reflect(k);
            lazy[k] = OM0;
        }
    }

    inline Monoid reflect(int k) { return lazy[k] == OM0 ? data[k] : g(data[k], lazy[k]); }

    inline void recalc(int k) {
        while (k >>= 1) data[k] = f(reflect(2 * k + 0), reflect(2 * k + 1));
    }

    inline void thrust(int k) {
        for (int i = height; i > 0; i--) propagate(k >> i);
    }

    void update(int a, int b, const OperatorMonoid &x) {
        thrust(a += sz);
        thrust(b += sz - 1);
        for (int l = a, r = b + 1; l < r; l >>= 1, r >>= 1) {
            if (l & 1)
                lazy[l] = h(lazy[l], x), ++l;
            if (r & 1)
                --r, lazy[r] = h(lazy[r], x);
        }
        recalc(a);
        recalc(b);
    }

    Monoid query(int a, int b) {
        thrust(a += sz);
        thrust(b += sz - 1);
        Monoid L = M1, R = M1;
        for (int l = a, r = b + 1; l < r; l >>= 1, r >>= 1) {
            if (l & 1)
                L = f(L, reflect(l++));
            if (r & 1)
                R = f(reflect(--r), R);
        }
        return f(L, R);
    }

    Monoid operator[](const int &k) { return query(k, k + 1); }

    template <typename C>
    int find_subtree(int a, const C &check, Monoid &M, bool type) {
        while (a < sz) {
            propagate(a);
            Monoid nxt = type ? f(reflect(2 * a + type), M) : f(M, reflect(2 * a + type));
            if (check(nxt))
                a = 2 * a + type;
            else
                M = nxt, a = 2 * a + 1 - type;
        }
        return a - sz;
    }

    template <typename C>
    int find_first(int a, const C &check) {
        Monoid L = M1;
        if (a <= 0) {
            if (check(f(L, reflect(1))))
                return find_subtree(1, check, L, false);
            return -1;
        }
        thrust(a + sz);
        int b = sz;
        for (a += sz, b += sz; a < b; a >>= 1, b >>= 1) {
            if (a & 1) {
                Monoid nxt = f(L, reflect(a));
                if (check(nxt))
                    return find_subtree(a, check, L, false);
                L = nxt;
                ++a;
            }
        }
        return -1;
    }

    template <typename C>
    int find_last(int b, const C &check) {
        Monoid R = M1;
        if (b >= sz) {
            if (check(f(reflect(1), R)))
                return find_subtree(1, check, R, true);
            return -1;
        }
        thrust(b + sz - 1);
        int a = sz;
        for (b += sz; a < b; a >>= 1, b >>= 1) {
            if (b & 1) {
                Monoid nxt = f(reflect(--b), R);
                if (check(nxt))
                    return find_subtree(b, check, R, true);
                R = nxt;
            }
        }
        return -1;
    }
};
// ----- library -------

ll largest_bit_cnt_sub(ll x, ll k) {
    if ((1LL << k) > x)
        return 0;
    else if ((1LL << (k + 1)) <= x)
        return 1LL << k;
    else
        return x - (1LL << k) + 1;
}

ll largest_bit_cnt(ll l, ll r, ll k) {
    if (l)
        return largest_bit_cnt_sub(r, k) - largest_bit_cnt_sub(l - 1, k);
    else
        return largest_bit_cnt_sub(r, k);
}

ll kbit_count(ll x, int k) { // x未満でkビット目が立ってるものの数
    if (x < 0)
        return 0;
    ll t = x >> (k + 1);
    ll ret = t << k;
    x %= 1LL << (k + 1);
    ret += max(0LL, x - (1LL << k));
    return ret;
}

ll kbit_count(ll l, ll r, int k) { // [l,r]でkビット目が立ってるものの数
    return kbit_count(r + 1, k) - kbit_count(l, k);
}

struct cond {
    int len;
    vector<vector<mint>> cnt;
    cond(pair<ll, ll> d) : cnt(vector<vector<mint>>(30, vector<mint>(4, 0))), len(1) {
        auto [l, r] = d;
        rep(k, 30) {
            cnt[k][0] = r - l + 1 - kbit_count(l, r, k);
            cnt[k][2] = kbit_count(l, r, k);
            cnt[k][3] = largest_bit_cnt(l, r, k);
        }
    }
    cond() : cnt(vector<vector<mint>>(30, vector<mint>(4, 0))), len(0) { rep(k, 30) cnt[k][0] = 1; }
};

cond f1(cond a, cond b) { 
    auto res = cond();
    res.len = a.len + b.len;
    rep(k, 30){
        res.cnt[k][0] = 0;
        rep(i, 4) rep(j, 4) {
            if(i%2 && j%2)
                continue;
            res.cnt[k][i ^ j] += a.cnt[k][i] * b.cnt[k][j];
        }
    }
    return res;
}

cond f2(cond a, pair<ll, ll> x) {
    if(x.first == -1)
        return a;
    cond res = cond();
    res.len = a.len;
    auto [l, r] = x;
    rep(k, 30) { 
        mint r2 = kbit_count(l, r,k), r0 = r - l + 1 - kbit_count(l, r, k), r3 = largest_bit_cnt(l, r, k) * a.len;
        mint nr[] = {r0, r2}, nnr[2], sr[] = {1, 0}, nsr[2];
        int n = a.len - 1;
        while(n != 0){
            if(n&1){
                nsr[0] = nr[0] * sr[0] + nr[1] * sr[1];
                nsr[1] = nr[0] * sr[1] + nr[1] * sr[0];
                rep(i, 2) sr[i] = nsr[i];
            }
            nnr[0] = nr[0] * nr[0] + nr[1] * nr[1];
            nnr[1] = nr[0] * nr[1] + nr[1] * nr[0];
            rep(i, 2) nr[i] = nnr[i];
            n >>= 1;
        }
        // cout << r3 << " " << sr[1] << endl;
        res.cnt[k][1] = r3 * sr[1];
        res.cnt[k][3] = r3 * sr[0];
        nsr[0] = r0 * sr[0] + r2 * sr[1];
        nsr[1] = r0 * sr[1] + r2 * sr[0];
        rep(i, 2) sr[i] = nsr[i];
        res.cnt[k][0] = sr[0];
        res.cnt[k][2] = sr[1];
    }
    return res;
}

pair<ll, ll> f3(pair<ll, ll> x, pair<ll, ll> y) { return y; }

int main() {
    ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    cout << fixed << setprecision(15);

    ll n;
    cin >> n;
    ll l[n], r[n];
    rep(i, n) cin >> l[i] >> r[i];
    LazySegmentTree<cond, pair<ll, ll>> seg(n, f1, f2, f3, cond(), {-1, -1});
    rep(i, n) seg.set(i, cond({l[i], r[i]}));
    seg.build();
    ll q;
    cin >> q;
    while (q--) { 
        ll t, lp, rp;
        cin >> t >> lp >> rp;
        lp--;
        if (t == 1) {
            ll nl, nr;
            cin >> nl >> nr;
            seg.update(lp, rp, {nl, nr});
        }
        else {
            mint ans = 0;
            auto res = seg.query(lp, rp);
            rep(k, 30) {
                ans += res.cnt[k][1];
            }
            cout << ans << endl;
        }
    }
}
accuracy: 1
time_ms: 1430
memory_kb: 58984
final_rank: 15

code_snippet: #pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#pragma GCC target("avx2")
#include <bits/stdc++.h>
using namespace std;
const long long MOD = 998244353;
struct monoid{
  array<array<array<long long, 4>, 4>, 30> M;
  monoid(int p){
    for (int i = 0; i < 4; i++){
      for (int j = 0; j < 4; j++){
        for (int k = 0; k < 30; k++){
          if (i == j){
            M[k][i][j] = p;
          } else {
            M[k][i][j] = 0;
          }
        }
      }
    }
  }
};
monoid f(monoid A, monoid B){
  monoid ans(0);
  for (int i = 0; i < 30; i++){
    for (int j = 0; j < 4; j++){
      for (int k = 0; k < 4; k++){
        if (A.M[i][j][k] > -0){
          for (int l = 0; l < 4; l++){
            ans.M[i][j][l] += A.M[i][j][k] * B.M[i][k][l];
            ans.M[i][j][l] %= MOD;
          }
        }
      }
    }
  }
  return ans;
}
monoid rp(monoid A, int x){
  monoid ans = A;
  while (x > 1){
    ans = f(ans, ans);
    x /= 2;
  }
  return ans;
}
struct lazy_segment_tree{
  int N;
  vector<monoid> ST, lazy;
  vector<bool> lazy_e;
  lazy_segment_tree(int N2){
    N = 1;
    while (N < N2){
      N *= 2;
    }
    ST = vector<monoid>(N * 2 - 1, monoid(1));
    lazy = vector<monoid>(N * 2 - 1, monoid(1));
    lazy_e = vector<bool>(N * 2 - 1, false);
  }
  void eval(int i, int l, int r){
    if (lazy_e[i]){
      if (i < N - 1){
        lazy[i * 2 + 1] = lazy[i];
        lazy_e[i * 2 + 1] = true;
        lazy[i * 2 + 2] = lazy[i];
        lazy_e[i * 2 + 2] = true;
      }
      ST[i] = rp(lazy[i], r - l);
      lazy_e[i] = false;
    }
  }
  void range_update(int L, int R, monoid M, int i, int l, int r){
    eval(i, l, r);
    if (R <= l || r <= L){
      return;
    } else if (L <= l && r <= R){
      lazy[i] = M;
      lazy_e[i] = true;
      eval(i, l, r);
    } else {
      int m = (l + r) / 2;
      range_update(L, R, M, i * 2 + 1, l, m);
      range_update(L, R, M, i * 2 + 2, m, r);
      ST[i] = f(ST[i * 2 + 1], ST[i * 2 + 2]);
    }
  }
  void range_update(int L, int R, monoid M){
    range_update(L, R, M, 0, 0, N);
  }
  monoid range_sum(int L, int R, int i, int l, int r){
    eval(i, l, r);
    if (r <= L || R <= l){
      return monoid(1);
    } else if (L <= l && r <= R){
      return ST[i];
    } else {
      int m = (l + r) / 2;
      return f(range_sum(L, R, i * 2 + 1, l, m), range_sum(L, R, i * 2 + 2, m, r));
    }
  }
  monoid range_sum(int L, int R){
    return range_sum(L, R, 0, 0, N);
  }
};
vector<vector<long long>> con(int L, int R, int b){
  int c1 = min(R, 1 << (b + 1)) - max(L, 1 << b);
  c1 = max(c1, 0);
  int ca = R >> (b + 1) << b;
  int r1 = R % (1 << (b + 1));
  ca += min(r1, 1 << b);
  int cb = L >> (b + 1) << b;
  int r2 = L % (1 << (b + 1));
  cb += min(r2, 1 << b);
  int c2 = ca - cb;
  int c3 = (R - L) - c2;
  vector<vector<long long>> tmp(4);
  tmp[0] = {c2, 0, c3, c1};
  tmp[1] = {0, c2, 0, c3};
  tmp[2] = {c3, c1, c2, 0};
  tmp[3] = {0, c3, 0, c2};
  return tmp;
}
monoid con2(int L, int R){
  monoid ans(0);
  for (int i = 0; i < 30; i++){
    vector<vector<long long>> A = con(L, R, i);
    for (int j = 0; j < 4; j++){
      for (int k = 0; k < 4; k++){
        ans.M[i][j][k] = A[j][k];
      }
    }
  }
  return ans;
}
int main(){
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  int N;
  cin >> N;
  vector<int> L(N), R(N);
  for (int i = 0; i < N; i++){
    cin >> L[i] >> R[i];
    R[i]++;
  }
  lazy_segment_tree ST(N);
  for (int i = 0; i < N; i++){
    ST.range_update(i, i + 1, con2(L[i], R[i]));
  }
  int Q;
  cin >> Q;
  for (int i = 0; i < Q; i++){
    int t;
    cin >> t;
    if (t == 1){
      int lp, rp, l, r;
      cin >> lp >> rp >> l >> r;
      lp--;
      r++;
      ST.range_update(lp, rp, con2(l, r));
    }
    if (t == 2){
      int lp, rp;
      cin >> lp >> rp;
      lp--;
      monoid res = ST.range_sum(lp, rp);
      long long ans = 0;
      for (int j = 0; j < 30; j++){
        ans += res.M[j][0][1];
      }
      ans %= MOD;
      cout << ans << "\n";
    }
  }
}
accuracy: 1
time_ms: 2380
memory_kb: 249292
final_rank: 17

code_snippet: #line 1 "005.cpp"
#include <bits/stdc++.h>
using namespace std::literals::string_literals;
using i64 = std::int_fast64_t;
using std::cout;
using std::cerr;
using std::endl;
using std::cin;

#if defined(DONLINE_JUDGE)
	#define NDEBUG
#elif defined(ONLINE_JUDGE)
	#define NDEBUG
#endif

template<typename T> std::vector<T> make_v(size_t a){return std::vector<T>(a);}
template<typename T, typename... Ts> auto make_v(size_t a, Ts... ts){
  return std::vector<decltype(make_v<T>(ts...))>(a, make_v<T>(ts...));
}

#include <vector>
#include <stack>
#include <cstdint>

#include <algorithm>
#include <limits>

#include <algorithm>

namespace cplib {
template<class T> struct affine {
	using value_type = T;

	value_type a;
	value_type b;

	constexpr affine(const value_type& a = 1, const value_type& b = 0): a(a), b(b) {}
	constexpr affine operator+(const affine& r) const { return affine{a + r.a, b + r.b}; }
	constexpr affine composite(const affine& r) const { return affine{a * r.a, a * r.b + b}; }

	constexpr value_type evaluate(const value_type& x) { return a * x + b; }
};
}


namespace cplib {
template<class T, T id = T{}> struct add_monoid {
	using value_type = T;

	T a;

	constexpr add_monoid(T a): a(a) {}
	static constexpr add_monoid operation(const add_monoid& l, const add_monoid& r) { return add_monoid{l.a + r.a}; }
	static constexpr add_monoid identity() { return add_monoid{id}; };
	static constexpr add_monoid inverse(const add_monoid& x) { return add_monoid{-x.a}; }
};

template<class T, T id = T{1}> struct mul_monoid {
	using value_type = T;

	T a;

	constexpr mul_monoid(T a): a(a) {}
	static constexpr mul_monoid operation(const mul_monoid& l, const mul_monoid& r) { return mul_monoid{l.a * r.a}; }
	static constexpr mul_monoid identity() { return mul_monoid{id}; };
};

template<class T, T id = T{}> struct max_monoid {
	using value_type = T;

	T a;

	constexpr max_monoid(T a): a(a) {}
	static constexpr max_monoid operation(const max_monoid& l, const max_monoid& r) { return max_monoid{std::max(l.a, r.a)}; }
	static constexpr max_monoid identity() { return max_monoid{id}; };
};

template<class T, T id = std::numeric_limits<T>::max()> struct min_monoid {
	using value_type = T;

	T a;

	constexpr min_monoid(T a): a(a) {}
	static constexpr min_monoid operation(const min_monoid& l, const min_monoid& r) { return min_monoid{std::min(l.a, r.a)}; }
	static constexpr min_monoid identity() { return min_monoid{id}; };
};

template<class T, T& id> struct monoid {
	using value_type = T;

	T a;

	constexpr monoid(T a): a(a) {}
	static constexpr monoid operation(const monoid& l, const monoid& r) { return monoid{l.a + r.a}; }
	static constexpr monoid identity() { return monoid{id}; }
	static constexpr monoid inverse(const monoid& x) { return monoid{x.a.inverse()}; }
};

template<class A, class B> struct cartesian_product_monoid {
	using value_type = std::pair<typename A::value_type, typename B::value_type>;

	value_type a;

	constexpr cartesian_product_monoid(const typename A::value_type& a): a(a, a) {}
	constexpr cartesian_product_monoid(const typename A::value_type& a, const typename B::value_type& b): a(a, b) {}
	constexpr cartesian_product_monoid(const value_type& a): a(a) {}
	static constexpr cartesian_product_monoid operation(const cartesian_product_monoid& l, const cartesian_product_monoid& r) {
		return cartesian_product_monoid{{A::operation(l.a.first, r.a.first).a, B::operation(l.a.second, r.a.second).a}};
	}
	static constexpr cartesian_product_monoid identity() { return cartesian_product_monoid{{A::identity().a, B::identity().a}}; }
	static constexpr cartesian_product_monoid inverse(const cartesian_product_monoid& x) {
		return cartesian_product_monoid{{A::inverse(x.a.first).a, B::inverse(x.a.second).a}};
	}
};

template<class T> struct affine_composite_monoid {
	using value_type = cplib::affine<T>;

	value_type a;

	constexpr affine_composite_monoid(const value_type& a): a(a) {}
	static constexpr affine_composite_monoid operation(const affine_composite_monoid& l,
													   const affine_composite_monoid& r) {
		return affine_composite_monoid{r.a.composite(l.a)};
	}
	static constexpr affine_composite_monoid identity() {
		return affine_composite_monoid{value_type()};
	}
};
}


namespace cplib {
template<class M, class E, class operation> class lazy_segment_tree {
public:
	using value_type 	= M;
	using T 			= typename value_type::value_type;
	using operator_type = E;
	using usize 		= std::uint_fast32_t;

	struct node_type {
		value_type value;
		operator_type lazy;

		node_type(const value_type& value, const operator_type& lazy): value(value), lazy(lazy) {}
	};

private:
	std::vector<node_type> data;

	value_type value(const node_type& x) const { return value_type{operation()(x.value.a, x.lazy.a)}; }
	usize countr_zeros(usize x) const { return __builtin_ctzll(x); }

	void add(operator_type& l, const operator_type& r) { l = operator_type::operation(l, r); }

	void propagate(usize idx) {
		add(data[idx * 2 + 0].lazy, data[idx].lazy);
		add(data[idx * 2 + 1].lazy, data[idx].lazy);
		data[idx].lazy = operator_type::identity();
	}
	void propagate_bound(usize idx) {
		if(idx == 0) return;

		std::stack<usize> order;

		idx >>= countr_zeros(idx);
		while(idx >>= 1) order.push(idx);
		while(!order.empty()){
			propagate(order.top());
			order.pop();
		}
	}

	void recalc(usize idx) { data[idx].value = value_type::operation(value(data[idx * 2 + 0]), value(data[idx * 2 + 1])); }
	void recalc_bound(usize idx) {
		if(idx == 0) return;

		idx >>= countr_zeros(idx);
		while(idx >>= 1) recalc(idx);
	}

public:
	lazy_segment_tree() = default;
	explicit lazy_segment_tree(usize n): data(n << 1, node_type(value_type::identity(), operator_type::identity())) {}
	template<class InputIt> explicit lazy_segment_tree(InputIt first, InputIt last)
	: lazy_segment_tree(std::distance(first, last)) {
		for(int index = 0; first != last; first++, index++) set(index, *first);
		build();
	}
	void build() { for(usize i = size() - 1; i > 0; i--) recalc(i); }

	usize size() { return data.size() >> 1; }
	bool empty() { return size() == 0; }
	void clear() { data.clear(); }
	void swap(lazy_segment_tree& r) { data.swap(r.data); }

	T get(usize i) { return fold(i, i + 1); }
	void set(usize i, const value_type& x) { data[i + size()].value = x; };

	void change(usize i, const value_type& x) {
		i += size();
		propagate_bound(((i >> 1) << 1) + 1);
		data[i] = node_type(x, operator_type::identity());
		recalc_bound(((i >> 1) << 1) + 1);
	}
	void update(usize i, const value_type& x) {
		i += size();
		propagate_bound(((i >> 1) << 1) + 1);
		data[i] = node_type(value_type::operation(value(data[i]), x), operator_type::identity());
		recalc_bound(((i >> 1) << 1) + 1);
	}

	T fold(usize first, usize last) {
		first += size();
		last  += size();
		propagate_bound(first);
		recalc_bound(first);
		propagate_bound(last);
		recalc_bound(last);

		value_type lval = value_type::identity();
		value_type rval = value_type::identity();
		while(first != last) {
			if(first & 1) {
				lval = value_type::operation(lval, value(data[first]));
				first++;
			}
			if(last  & 1) {
				last--;
				rval = value_type::operation(value(data[last]), rval);
			}
			first >>= 1;
			last  >>= 1;
		}
		return value_type::operation(lval, rval).a;
	}

	void update(usize first, usize last, const operator_type& x) {
		first += size();
		last  += size();
		usize first_tmp = first;
		usize last_tmp  = last;
		propagate_bound(first);
		propagate_bound(last);
		while(first != last) {
			if(first & 1) {
				add(data[first].lazy, x);
				first++;
			}
			if(last  & 1) {
				last--;
				add(data[last].lazy, x);
			}
			first >>= 1;
			last >>= 1;
		}
		recalc_bound(first_tmp);
		recalc_bound(last_tmp);
	}
};
}


#ifndef INCLUDED_MODINT_HPP
#define INCLUDED_MODINT_HPP

#include <iostream>

namespace cplib {
template <std::uint_fast64_t Modulus>
class modint {
	using u32 = std::uint_fast32_t;
	using u64 = std::uint_fast64_t;
	using i32 = std::int_fast32_t;
	using i64 = std::int_fast64_t;

	inline u64 apply(i64 x) { return (x < 0 ? x + Modulus : x); };

public:
	u64 a;
	static constexpr u64 mod = Modulus;

	constexpr modint(const i64& x = 0) noexcept: a(apply(x % (i64)Modulus)) {}

	constexpr modint operator+(const modint& rhs) const noexcept { return modint(*this) += rhs; }
	constexpr modint operator-(const modint& rhs) const noexcept { return modint(*this) -= rhs; }
	constexpr modint operator*(const modint& rhs) const noexcept { return modint(*this) *= rhs; }
	constexpr modint operator/(const modint& rhs) const noexcept { return modint(*this) /= rhs; }
	constexpr modint operator^(const u64& k) const noexcept { return modint(*this) ^= k; }
	constexpr modint operator^(const modint& k) const noexcept { return modint(*this) ^= k.value(); }
	constexpr modint operator-() const noexcept { return modint(Modulus - a); }
	constexpr modint operator++() noexcept { return (*this) = modint(*this) + 1; }
	constexpr modint operator--() noexcept { return (*this) = modint(*this) - 1; }
	const bool operator==(const modint& rhs) const noexcept { return a == rhs.a; };
	const bool operator!=(const modint& rhs) const noexcept { return a != rhs.a; };
	const bool operator<=(const modint& rhs) const noexcept { return a <= rhs.a; };
	const bool operator>=(const modint& rhs) const noexcept { return a >= rhs.a; };
	const bool operator<(const modint& rhs) const noexcept { return a < rhs.a; };
	const bool operator>(const modint& rhs) const noexcept { return a > rhs.a; };
	constexpr modint& operator+=(const modint& rhs) noexcept {
		a += rhs.a;
		if (a >= Modulus) a -= Modulus;
		return *this;
	}
	constexpr modint& operator-=(const modint& rhs) noexcept {
		if (a < rhs.a) a += Modulus;
		a -= rhs.a;
		return *this;
	}
	constexpr modint& operator*=(const modint& rhs) noexcept {
		a = a * rhs.a % Modulus;
		return *this;
	}
	constexpr modint& operator/=(modint rhs) noexcept {
		u64 exp = Modulus - 2;
		while (exp) {
			if (exp % 2) (*this) *= rhs;

			rhs *= rhs;
			exp /= 2;
		}
		return *this;
	}
	constexpr modint& operator^=(u64 k) noexcept {
		auto b = modint(1);
		while(k) {
			if(k & 1) b = b * (*this);
			(*this) *= (*this);
			k >>= 1;
		}
		return (*this) = b;
	}
	constexpr modint& operator=(const modint& rhs) noexcept {
		a = rhs.a;
		return (*this);
	}

	const modint inverse() const {
		return modint(1) / *this;
	}
	const modint power(i64 k) const {
		if(k < 0) return modint(*this).inverse() ^ (-k);
		return modint(*this) ^ k;
	}

	explicit operator bool() const { return a; }
	explicit operator u64() const { return a; }
	constexpr u64& value() noexcept { return a; }
	constexpr const u64& value() const noexcept { return a; }

	friend std::ostream& operator<<(std::ostream& os, const modint& p) {
		return os << p.a;
	}
	friend std::istream& operator>>(std::istream& is, modint& p) {
		u64 t;
		is >> t;
		p = modint(t);
		return is;
	}
};
}

#endif

using mint = cplib::modint<998244353>;

#define NDEBUG

constexpr int MOD = 998244353;

inline i64 countA1(int k, int L, int R) { // [L, R] で k-bit が立っているものの個数
	int T = 1 << k + 1, H = 1 << k;
	auto lemma = [&](int X) -> int { // [0, X) で
		return X / T * H + std::max(0, X % T - H);
	};
	return lemma(R + 1) - lemma(L);
}

inline i64 countA0(int k, int L, int R) { // [L, R] で k-bit が立っていないものの個数
	return (R - L + 1) - countA1(k, L, R);
}

inline i64 countB1(int k, int L, int R) { // [L, R] で k-bit が最上位 bit なものの個数
	int L2 = std::max(L, 1 << k);
	int R2 = std::min(R, (1 << k + 1) - 1);
	return std::max(0, R2 - L2 + 1);
}

inline void add(i64& x, i64 y) { (x += y % MOD) %= MOD; }

struct mat {
	mint a, b, c, d;

	mat(): a(0), b(0), c(0), d(0) {}
	mat(mint a, mint b, mint c, mint d): a(a), b(b), c(c), d(d) {}
	mat operator*(mat r) const {
		return mat(a * r.a + b * r.c, a * r.b + b * r.d,
				   c * r.a + d * r.c, c * r.b + d * r.d);
	}
	mat operator^(int k) const {
		mat x = *this, ret = mat(1, 0, 0, 1);
		while(k) {
			if(k & 1) ret = ret * x;
			x = x * x;
			k >>= 1;
		}
		return ret;
	}
	mat operator+(mat r) const {
		return mat(a + r.a, b + r.b, c + r.c, d + r.d);
	}
};

struct node {
	int len, k;
	mat x, y;

	node(int len, int k, mat x, mat y): len(len), k(k), x(x), y(y) {}
	node(int a, int b, int k): len(1), k(k) {
		mint c0 = countA0(k, a, b);
		mint c1 = countA1(k, a, b);
		mint c2 = countB1(k, a, b);

		x = mat(c0, c1, c1, c0);
		y = mat(0, c2, c2, 0);
	}

	node operator+(node r) const {
		return node(len + r.len, std::max(k, r.k),
				x * r.x, x * r.y + y * r.x);
	}
} nid(0, 0, 0);

struct lazy {
	int a, b;

	lazy(int a, int b): a(a), b(b) {}
	lazy operator+(lazy r) const {
		if(r.a) return lazy(r.a, r.b);
		return *this;
	}
} lid(0, 0);

struct op {
	node operator()(node l, lazy r) const {
		if(!r.a) return l;
		int a = r.a, b = r.b, k = l.k, len = l.len;
		mint c0 = countA0(k, a, b), c1 = countA1(k, a, b), c2 = countB1(k, a, b);

		mat m(c0, c1, c1, c0);
		mat w = m ^ (len - 1);
		mat x = w * m;
		mat y =	w * mat(0, c2, c2, 0) * mat(len, 0, 0, len);
		return node(l.len, l.k, x, y);
	}
};

int main() {
	int n; scanf("%d", &n);
	std::vector<int> L(n), R(n); for(int i = 0; i < n; i++) scanf("%d%d", &L[i], &R[i]);

	std::vector<cplib::lazy_segment_tree<cplib::monoid<node, nid>,
										 cplib::monoid<lazy, lid>,
										 op>> seg(30);
	for(int k = 0; k < 30; k++) {
		seg[k] = cplib::lazy_segment_tree<cplib::monoid<node, nid>,
										 cplib::monoid<lazy, lid>,
										 op>(n);
		for(int i = 0; i < n; i++) seg[k].set(i, node(L[i], R[i], k));
		seg[k].build();
	}

	int q; scanf("%d", &q);
	while(q--) {
		int type; scanf("%d", &type);

		if (type == 1) {
			int li, ri, l, r; scanf("%d%d%d%d", &li, &ri, &l, &r); li--;
			for(int k = 0; k < 30; k++) seg[k].update(li, ri, lazy(l, r));
		} else {
			int li, ri; scanf("%d%d", &li, &ri); li--;

			mint ans = 0;
			for(int k = 0; k < 30; k++) ans += seg[k].fold(li, ri).y.a;
			printf("%lld\n", ans.value());
		}

		#ifndef NDEBUG
		printf("L: "); for(int e: L) printf("%d ", e); printf("\n");
		printf("R: "); for(int e: R) printf("%d ", e); printf("\n");
		#endif
	}
	return 0;
}
accuracy: 1
time_ms: 990
memory_kb: 50096
final_rank: 11

code_snippet: //#include "atcoder/all"
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>

#include <cassert>
#include <numeric>
#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#endif


#include <utility>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {

namespace internal {

// @param m `1 <= m`
// @return x mod m
constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}

// Fast modular multiplication by barrett reduction
// Reference: https://en.wikipedia.org/wiki/Barrett_reduction
// NOTE: reconsider after Ice Lake
struct barrett {
    unsigned int _m;
    unsigned long long im;

    // @param m `1 <= m < 2^31`
    explicit barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}

    // @return m
    unsigned int umod() const { return _m; }

    // @param a `0 <= a < m`
    // @param b `0 <= b < m`
    // @return `a * b % m`
    unsigned int mul(unsigned int a, unsigned int b) const {
        // [1] m = 1
        // a = b = im = 0, so okay

        // [2] m >= 2
        // im = ceil(2^64 / m)
        // -> im * m = 2^64 + r (0 <= r < m)
        // let z = a*b = c*m + d (0 <= c, d < m)
        // a*b * im = (c*m + d) * im = c*(im*m) + d*im = c*2^64 + c*r + d*im
        // c*r + d*im < m * m + m * im < m * m + 2^64 + m <= 2^64 + m * (m + 1) < 2^64 * 2
        // ((ab * im) >> 64) == c or c + 1
        unsigned long long z = a;
        z *= b;
#ifdef _MSC_VER
        unsigned long long x;
        _umul128(z, im, &x);
#else
        unsigned long long x =
            (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
        unsigned int v = (unsigned int)(z - x * _m);
        if (_m <= v) v += _m;
        return v;
    }
};

// @param n `0 <= n`
// @param m `1 <= m`
// @return `(x ** n) % m`
constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
    if (m == 1) return 0;
    unsigned int _m = (unsigned int)(m);
    unsigned long long r = 1;
    unsigned long long y = safe_mod(x, m);
    while (n) {
        if (n & 1) r = (r * y) % _m;
        y = (y * y) % _m;
        n >>= 1;
    }
    return r;
}

// Reference:
// M. Forisek and J. Jancina,
// Fast Primality Testing for Integers That Fit into a Machine Word
// @param n `0 <= n`
constexpr bool is_prime_constexpr(int n) {
    if (n <= 1) return false;
    if (n == 2 || n == 7 || n == 61) return true;
    if (n % 2 == 0) return false;
    long long d = n - 1;
    while (d % 2 == 0) d /= 2;
    constexpr long long bases[3] = {2, 7, 61};
    for (long long a : bases) {
        long long t = d;
        long long y = pow_mod_constexpr(a, t, n);
        while (t != n - 1 && y != 1 && y != n - 1) {
            y = y * y % n;
            t <<= 1;
        }
        if (y != n - 1 && t % 2 == 0) {
            return false;
        }
    }
    return true;
}
template <int n> constexpr bool is_prime = is_prime_constexpr(n);

// @param b `1 <= b`
// @return pair(g, x) s.t. g = gcd(a, b), xa = g (mod b), 0 <= x < b/g
constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
    a = safe_mod(a, b);
    if (a == 0) return {b, 0};

    // Contracts:
    // [1] s - m0 * a = 0 (mod b)
    // [2] t - m1 * a = 0 (mod b)
    // [3] s * |m1| + t * |m0| <= b
    long long s = b, t = a;
    long long m0 = 0, m1 = 1;

    while (t) {
        long long u = s / t;
        s -= t * u;
        m0 -= m1 * u;  // |m1 * u| <= |m1| * s <= b

        // [3]:
        // (s - t * u) * |m1| + t * |m0 - m1 * u|
        // <= s * |m1| - t * u * |m1| + t * (|m0| + |m1| * u)
        // = s * |m1| + t * |m0| <= b

        auto tmp = s;
        s = t;
        t = tmp;
        tmp = m0;
        m0 = m1;
        m1 = tmp;
    }
    // by [3]: |m0| <= b/g
    // by g != b: |m0| < b/g
    if (m0 < 0) m0 += b / s;
    return {s, m0};
}

// Compile time primitive root
// @param m must be prime
// @return primitive root (and minimum in now)
constexpr int primitive_root_constexpr(int m) {
    if (m == 2) return 1;
    if (m == 167772161) return 3;
    if (m == 469762049) return 3;
    if (m == 754974721) return 11;
    if (m == 998244353) return 3;
    int divs[20] = {};
    divs[0] = 2;
    int cnt = 1;
    int x = (m - 1) / 2;
    while (x % 2 == 0) x /= 2;
    for (int i = 3; (long long)(i)*i <= x; i += 2) {
        if (x % i == 0) {
            divs[cnt++] = i;
            while (x % i == 0) {
                x /= i;
            }
        }
    }
    if (x > 1) {
        divs[cnt++] = x;
    }
    for (int g = 2;; g++) {
        bool ok = true;
        for (int i = 0; i < cnt; i++) {
            if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                ok = false;
                break;
            }
        }
        if (ok) return g;
    }
}
template <int m> constexpr int primitive_root = primitive_root_constexpr(m);

// @param n `n < 2^32`
// @param m `1 <= m < 2^32`
// @return sum_{i=0}^{n-1} floor((ai + b) / m) (mod 2^64)
unsigned long long floor_sum_unsigned(unsigned long long n,
                                      unsigned long long m,
                                      unsigned long long a,
                                      unsigned long long b) {
    unsigned long long ans = 0;
    while (true) {
        if (a >= m) {
            ans += n * (n - 1) / 2 * (a / m);
            a %= m;
        }
        if (b >= m) {
            ans += n * (b / m);
            b %= m;
        }

        unsigned long long y_max = a * n + b;
        if (y_max < m) break;
        // y_max < m * (n + 1)
        // floor(y_max / m) <= n
        n = (unsigned long long)(y_max / m);
        b = (unsigned long long)(y_max % m);
        std::swap(m, a);
    }
    return ans;
}

}  // namespace internal

}  // namespace atcoder


#include <cassert>
#include <numeric>
#include <type_traits>

namespace atcoder {

namespace internal {

#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value ||
                                  std::is_same<T, __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int128 =
    typename std::conditional<std::is_same<T, __uint128_t>::value ||
                                  std::is_same<T, unsigned __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using make_unsigned_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value,
                              __uint128_t,
                              unsigned __int128>;

template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
                                                  is_signed_int128<T>::value ||
                                                  is_unsigned_int128<T>::value,
                                              std::true_type,
                                              std::false_type>::type;

template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                 std::is_signed<T>::value) ||
                                                    is_signed_int128<T>::value,
                                                std::true_type,
                                                std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<(is_integral<T>::value &&
                               std::is_unsigned<T>::value) ||
                                  is_unsigned_int128<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<
    is_signed_int128<T>::value,
    make_unsigned_int128<T>,
    typename std::conditional<std::is_signed<T>::value,
                              std::make_unsigned<T>,
                              std::common_type<T>>::type>::type;

#else

template <class T> using is_integral = typename std::is_integral<T>;

template <class T>
using is_signed_int =
    typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<is_integral<T>::value &&
                                  std::is_unsigned<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
                                              std::make_unsigned<T>,
                                              std::common_type<T>>::type;

#endif

template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;

template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;

template <class T> using to_unsigned_t = typename to_unsigned<T>::type;

}  // namespace internal

}  // namespace atcoder


namespace atcoder {

namespace internal {

struct modint_base {};
struct static_modint_base : modint_base {};

template <class T> using is_modint = std::is_base_of<modint_base, T>;
template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;

}  // namespace internal

template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
struct static_modint : internal::static_modint_base {
    using mint = static_modint;

  public:
    static constexpr int mod() { return m; }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    static_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    static_modint(T v) {
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    static_modint(T v) {
        _v = (unsigned int)(v % umod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        if (prime) {
            assert(_v);
            return pow(umod() - 2);
        } else {
            auto eg = internal::inv_gcd(_v, m);
            assert(eg.first == 1);
            return eg.second;
        }
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
    static constexpr bool prime = internal::is_prime<m>;
};

template <int id> struct dynamic_modint : internal::modint_base {
    using mint = dynamic_modint;

  public:
    static int mod() { return (int)(bt.umod()); }
    static void set_mod(int m) {
        assert(1 <= m);
        bt = internal::barrett(m);
    }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    dynamic_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        long long x = (long long)(v % (long long)(mod()));
        if (x < 0) x += mod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        _v = (unsigned int)(v % mod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        _v = bt.mul(_v, rhs._v);
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        auto eg = internal::inv_gcd(_v, mod());
        assert(eg.first == 1);
        return eg.second;
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static internal::barrett bt;
    static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt(998244353);

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

namespace internal {

template <class T>
using is_static_modint = std::is_base_of<internal::static_modint_base, T>;

template <class T>
using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}  // namespace internal

}  // namespace atcoder

//#include "atcoder/string"
//#include "atcoder/convolution"
//#include "gitgit/segtree.hpp"
//#include "atcoder/fenwicktree"
using namespace std;
using namespace atcoder;
#define int long long
#define ppp pair<pair<mint,mint>,pair<mint,mint>>
  template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return 1; } return 0; }
//const int MOD =1e9+7;
const int MOD =998244353;
const long long M1=167772161,M2=469762049,M3=1224736769;
//const int MOD =31607;
using mint = static_modint<MOD>;
//using mint = double;
//using mint = modint;
ostream& operator << (ostream& ost, const mint& m){ost << m.val();return ost;}
istream& operator >> (istream& ost,  mint& m){int a;ost >> a;m=a;return ost;}
int ceil_pow2(int n) {
    int x = 0;
    while ((1U << x) < (unsigned int)(n)) x++;
    return x;
}
template <class S,class F,typename A,typename B,typename C> struct lazytree {
  public:
    lazytree(S(*s)(S,S),S e,A op,B mapping , C composition,F(*f)(F,F)) : lazytree(s,0,e,op,mapping,composition,f) {}
    lazytree(S(*s)(S,S),int n,S e,A op,B mapping , C composition,F(*f)(F,F)) : lazytree(s,std::vector<S>(n, e),e,op,mapping,composition,f) {}
    lazytree(S(*s)(S,S),const std::vector<S>& v,S e,A op,B mapping , C composition,F(*f)(F,F)) : _n(signed(v.size())),e(e),op(op),mapping(mapping),composition(composition)
     {
        log = ceil_pow2(_n);
        size = 1 << log;
        d = std::vector<S>(2 * size, e);
        lz = std::vector<optional<F>>(size,std::nullopt);
        for (int i = 0; i < _n; i++) d[size + i] = v[i];
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }

    void set(int p, S x) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = x;
        for (int i = 1; i <= log; i++) update(p >> i);
    }

    S get(int p) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        return d[p];
    }

    S prod(int l, int r) {
        assert(0 <= l && l <= r && r <= _n);
        if (l == r) return e;

        l += size;
        r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push(r >> i);
        }

        S sml = e, smr = e;
        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }

        return op(sml, smr);
    }

    S all_prod() { return d[1]; }

    void apply(int p, F f) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = mapping(f, d[p]);
        for (int i = 1; i <= log; i++) update(p >> i);
    }
    void apply(int l, int r, F f) {
        assert(0 <= l && l <= r && r <= _n);
        if (l == r) return;

        l += size;
        r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push((r - 1) >> i);
        }

        for(int l2 = l, r2 = r; l2 < r2; l2 >>= 1, r2 >>= 1){   
            if (l2 & 1) all_apply(l2++, f);
            if (r2 & 1) all_apply(--r2, f);
        }

        for (int i = 1; i <= log; i++) {
            if (((l >> i) << i) != l) update(l >> i);
            if (((r >> i) << i) != r) update((r - 1) >> i);
        }
    }

    template <bool (*g)(S)> int max_right(int l) {
        return max_right(l, [](S x) { return g(x); });
    }
    template <class G> int max_right(int l, G g) {
        assert(0 <= l && l <= _n);
        assert(g(e));
        if (l == _n) return _n;
        l += size;
        for (int i = log; i >= 1; i--) push(l >> i);
        S sm = e;
        do {
            while (l % 2 == 0) l >>= 1;
            if (!g(op(sm, d[l]))) {
                while (l < size) {
                    push(l);
                    l = (2 * l);
                    if (g(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - size;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return _n;
    }

    template <bool (*g)(S)> int min_left(int r) {
        return min_left(r, [](S x) { return g(x); });
    }
    template <class G> int min_left(int r, G g) {
        assert(0 <= r && r <= _n);
        assert(g(e));
        if (r == 0) return 0;
        r += size;
        for (int i = log; i >= 1; i--) push((r - 1) >> i);
        S sm = e;
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!g(op(d[r], sm))) {
                while (r < size) {
                    push(r);
                    r = (2 * r + 1);
                    if (g(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - size;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

  private:
    int _n, size, log;
    std::vector<S> d;
    std::vector<optional<F>> lz;
    A op;
    B mapping;
    C composition;
    S e;
    void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }
    void all_apply(int k, F f) {
      F g=f;
      int k2=k;
      
      while(k2<size){
        F g2=g;
        g=op(g2,g);
        k2*=2;
      
      }
     
        d[k] = mapping(g, d[k]);
        if (k < size) lz[k] =(lz[k] ? composition(f, *lz[k]):f);
    }
    void push(int k) {
        if(lz[k]){
            all_apply(2 * k, *lz[k]);
            all_apply(2 * k + 1, *lz[k]);
            lz[k] = std::nullopt;
        }
    }

};
template <class S,typename A,typename B,typename C>
auto maketree(int n,S a,A b,B c,C d){return lazytree(+b,n,a,b,c,d,+d);}
int n,l[20000],r[20000],q,t[10000],lp[10000],rp[10000],lx[10000],rx[10000];
mint ans[10000]={};
void solve(int x){
  auto tr=maketree(n,make_pair(make_pair((mint)1,(mint)0),make_pair((mint)0,(mint)0)),
  [](ppp a,ppp b)->ppp{
   pair<mint,mint>p,q1,q2;
   p={a.first.first*b.first.first+a.first.second*b.first.second,a.first.first*b.first.second+a.first.second*b.first.first};
   q1={a.second.first*b.first.first+a.second.second*b.first.second,a.second.first*b.first.second+a.second.second*b.first.first};
   q2={a.first.first*b.second.first+a.first.second*b.second.second,a.first.first*b.second.second+a.first.second*b.second.first};
   q1.first+=q2.first;
   q1.second+=q2.second;
   return {p,q1};
  },[](ppp f,ppp a)->ppp{return f;},[](ppp g,ppp f)->ppp{return g;});
  for(int i=0;i<n+q;i++){
    if(i>=n&&t[i-n]==2){
        ans[i-n]+=tr.prod(lp[i-n],rp[i-n]).second.first;
       
        continue;
    }
    int lon,lz,ron,rz;
    if(l[i]&(1ll<<x)){
      lon=((l[i]>>(x+1))<<x)+l[i]%(1ll<<x);
      lz=l[i]-lon;
    }else{
      lz=((l[i]>>(x+1))<<x)+l[i]%(1ll<<x);
      lon=l[i]-lz;
    }
    if(r[i]&(1ll<<x)){
      ron=((r[i]>>(x+1))<<x)+r[i]%(1ll<<x);
      rz=r[i]-ron;
    }else{
      rz=((r[i]>>(x+1))<<x)+r[i]%(1ll<<x);
      ron=r[i]-rz;
    }
    if(i<n)tr.set(i,{make_pair((mint)rz-lz,(mint)ron-lon),make_pair((mint)0,(mint)max(0ll,min(r[i],1ll<<(x+1))-max(l[i],1ll<<x)))});
    else{
      tr.apply(lp[i-n],rp[i-n],{make_pair((mint)rz-lz,(mint)ron-lon),make_pair((mint)0,(mint)max(0ll,min(r[i],1ll<<(x+1))-max(l[i],1ll<<x)))});
         
          
    }

  }
  

}
signed main(){
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  cin>>n;
  for(int i=0;i<n;i++){
    cin>>l[i]>>r[i];
    r[i]++;
  }
  cin>>q;
  for(int i=0;i<q;i++){
    cin>>t[i]>>lp[i]>>rp[i];
    lp[i]--;
    if(t[i]==1){
      cin>>l[i+n]>>r[i+n];
      r[i+n]++;
    }
  }
  for(int i=0;i<30;i++)solve(i);
  for(int i=0;i<q;i++)if(t[i]==2)cout<<ans[i]<<endl;

}
accuracy: 1
time_ms: 560
memory_kb: 4756
final_rank: 8

code_snippet: //#include "atcoder/all"
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>

#include <cassert>
#include <numeric>
#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#endif


#include <utility>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {

namespace internal {

// @param m `1 <= m`
// @return x mod m
constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}

// Fast modular multiplication by barrett reduction
// Reference: https://en.wikipedia.org/wiki/Barrett_reduction
// NOTE: reconsider after Ice Lake
struct barrett {
    unsigned int _m;
    unsigned long long im;

    // @param m `1 <= m < 2^31`
    explicit barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}

    // @return m
    unsigned int umod() const { return _m; }

    // @param a `0 <= a < m`
    // @param b `0 <= b < m`
    // @return `a * b % m`
    unsigned int mul(unsigned int a, unsigned int b) const {
        // [1] m = 1
        // a = b = im = 0, so okay

        // [2] m >= 2
        // im = ceil(2^64 / m)
        // -> im * m = 2^64 + r (0 <= r < m)
        // let z = a*b = c*m + d (0 <= c, d < m)
        // a*b * im = (c*m + d) * im = c*(im*m) + d*im = c*2^64 + c*r + d*im
        // c*r + d*im < m * m + m * im < m * m + 2^64 + m <= 2^64 + m * (m + 1) < 2^64 * 2
        // ((ab * im) >> 64) == c or c + 1
        unsigned long long z = a;
        z *= b;
#ifdef _MSC_VER
        unsigned long long x;
        _umul128(z, im, &x);
#else
        unsigned long long x =
            (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
        unsigned int v = (unsigned int)(z - x * _m);
        if (_m <= v) v += _m;
        return v;
    }
};

// @param n `0 <= n`
// @param m `1 <= m`
// @return `(x ** n) % m`
constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
    if (m == 1) return 0;
    unsigned int _m = (unsigned int)(m);
    unsigned long long r = 1;
    unsigned long long y = safe_mod(x, m);
    while (n) {
        if (n & 1) r = (r * y) % _m;
        y = (y * y) % _m;
        n >>= 1;
    }
    return r;
}

// Reference:
// M. Forisek and J. Jancina,
// Fast Primality Testing for Integers That Fit into a Machine Word
// @param n `0 <= n`
constexpr bool is_prime_constexpr(int n) {
    if (n <= 1) return false;
    if (n == 2 || n == 7 || n == 61) return true;
    if (n % 2 == 0) return false;
    long long d = n - 1;
    while (d % 2 == 0) d /= 2;
    constexpr long long bases[3] = {2, 7, 61};
    for (long long a : bases) {
        long long t = d;
        long long y = pow_mod_constexpr(a, t, n);
        while (t != n - 1 && y != 1 && y != n - 1) {
            y = y * y % n;
            t <<= 1;
        }
        if (y != n - 1 && t % 2 == 0) {
            return false;
        }
    }
    return true;
}
template <int n> constexpr bool is_prime = is_prime_constexpr(n);

// @param b `1 <= b`
// @return pair(g, x) s.t. g = gcd(a, b), xa = g (mod b), 0 <= x < b/g
constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
    a = safe_mod(a, b);
    if (a == 0) return {b, 0};

    // Contracts:
    // [1] s - m0 * a = 0 (mod b)
    // [2] t - m1 * a = 0 (mod b)
    // [3] s * |m1| + t * |m0| <= b
    long long s = b, t = a;
    long long m0 = 0, m1 = 1;

    while (t) {
        long long u = s / t;
        s -= t * u;
        m0 -= m1 * u;  // |m1 * u| <= |m1| * s <= b

        // [3]:
        // (s - t * u) * |m1| + t * |m0 - m1 * u|
        // <= s * |m1| - t * u * |m1| + t * (|m0| + |m1| * u)
        // = s * |m1| + t * |m0| <= b

        auto tmp = s;
        s = t;
        t = tmp;
        tmp = m0;
        m0 = m1;
        m1 = tmp;
    }
    // by [3]: |m0| <= b/g
    // by g != b: |m0| < b/g
    if (m0 < 0) m0 += b / s;
    return {s, m0};
}

// Compile time primitive root
// @param m must be prime
// @return primitive root (and minimum in now)
constexpr int primitive_root_constexpr(int m) {
    if (m == 2) return 1;
    if (m == 167772161) return 3;
    if (m == 469762049) return 3;
    if (m == 754974721) return 11;
    if (m == 998244353) return 3;
    int divs[20] = {};
    divs[0] = 2;
    int cnt = 1;
    int x = (m - 1) / 2;
    while (x % 2 == 0) x /= 2;
    for (int i = 3; (long long)(i)*i <= x; i += 2) {
        if (x % i == 0) {
            divs[cnt++] = i;
            while (x % i == 0) {
                x /= i;
            }
        }
    }
    if (x > 1) {
        divs[cnt++] = x;
    }
    for (int g = 2;; g++) {
        bool ok = true;
        for (int i = 0; i < cnt; i++) {
            if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                ok = false;
                break;
            }
        }
        if (ok) return g;
    }
}
template <int m> constexpr int primitive_root = primitive_root_constexpr(m);

// @param n `n < 2^32`
// @param m `1 <= m < 2^32`
// @return sum_{i=0}^{n-1} floor((ai + b) / m) (mod 2^64)
unsigned long long floor_sum_unsigned(unsigned long long n,
                                      unsigned long long m,
                                      unsigned long long a,
                                      unsigned long long b) {
    unsigned long long ans = 0;
    while (true) {
        if (a >= m) {
            ans += n * (n - 1) / 2 * (a / m);
            a %= m;
        }
        if (b >= m) {
            ans += n * (b / m);
            b %= m;
        }

        unsigned long long y_max = a * n + b;
        if (y_max < m) break;
        // y_max < m * (n + 1)
        // floor(y_max / m) <= n
        n = (unsigned long long)(y_max / m);
        b = (unsigned long long)(y_max % m);
        std::swap(m, a);
    }
    return ans;
}

}  // namespace internal

}  // namespace atcoder


#include <cassert>
#include <numeric>
#include <type_traits>

namespace atcoder {

namespace internal {

#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value ||
                                  std::is_same<T, __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int128 =
    typename std::conditional<std::is_same<T, __uint128_t>::value ||
                                  std::is_same<T, unsigned __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using make_unsigned_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value,
                              __uint128_t,
                              unsigned __int128>;

template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
                                                  is_signed_int128<T>::value ||
                                                  is_unsigned_int128<T>::value,
                                              std::true_type,
                                              std::false_type>::type;

template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                 std::is_signed<T>::value) ||
                                                    is_signed_int128<T>::value,
                                                std::true_type,
                                                std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<(is_integral<T>::value &&
                               std::is_unsigned<T>::value) ||
                                  is_unsigned_int128<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<
    is_signed_int128<T>::value,
    make_unsigned_int128<T>,
    typename std::conditional<std::is_signed<T>::value,
                              std::make_unsigned<T>,
                              std::common_type<T>>::type>::type;

#else

template <class T> using is_integral = typename std::is_integral<T>;

template <class T>
using is_signed_int =
    typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<is_integral<T>::value &&
                                  std::is_unsigned<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
                                              std::make_unsigned<T>,
                                              std::common_type<T>>::type;

#endif

template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;

template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;

template <class T> using to_unsigned_t = typename to_unsigned<T>::type;

}  // namespace internal

}  // namespace atcoder


namespace atcoder {

namespace internal {

struct modint_base {};
struct static_modint_base : modint_base {};

template <class T> using is_modint = std::is_base_of<modint_base, T>;
template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;

}  // namespace internal

template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
struct static_modint : internal::static_modint_base {
    using mint = static_modint;

  public:
    static constexpr int mod() { return m; }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    static_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    static_modint(T v) {
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    static_modint(T v) {
        _v = (unsigned int)(v % umod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        if (prime) {
            assert(_v);
            return pow(umod() - 2);
        } else {
            auto eg = internal::inv_gcd(_v, m);
            assert(eg.first == 1);
            return eg.second;
        }
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
    static constexpr bool prime = internal::is_prime<m>;
};

template <int id> struct dynamic_modint : internal::modint_base {
    using mint = dynamic_modint;

  public:
    static int mod() { return (int)(bt.umod()); }
    static void set_mod(int m) {
        assert(1 <= m);
        bt = internal::barrett(m);
    }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    dynamic_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        long long x = (long long)(v % (long long)(mod()));
        if (x < 0) x += mod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        _v = (unsigned int)(v % mod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        _v = bt.mul(_v, rhs._v);
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        auto eg = internal::inv_gcd(_v, mod());
        assert(eg.first == 1);
        return eg.second;
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static internal::barrett bt;
    static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt(998244353);

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

namespace internal {

template <class T>
using is_static_modint = std::is_base_of<internal::static_modint_base, T>;

template <class T>
using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}  // namespace internal

}  // namespace atcoder

//#include "atcoder/string"
//#include "atcoder/convolution"
//#include "gitgit/segtree.hpp"
//#include "atcoder/fenwicktree"
using namespace std;
using namespace atcoder;
#define int long long
#define ppp pair<pair<mint,mint>,pair<mint,mint>>
  template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return 1; } return 0; }
//const int MOD =1e9+7;
const int MOD =998244353;
const long long M1=167772161,M2=469762049,M3=1224736769;
//const int MOD =31607;
using mint = static_modint<MOD>;
//using mint = double;
//using mint = modint;
ostream& operator << (ostream& ost, const mint& m){ost << m.val();return ost;}
istream& operator >> (istream& ost,  mint& m){int a;ost >> a;m=a;return ost;}
int ceil_pow2(int n) {
    int x = 0;
    while ((1U << x) < (unsigned int)(n)) x++;
    return x;
}
template <class S,class F,typename A,typename B,typename C> struct lazytree {
  public:
    lazytree(S(*s)(S,S),S e,A op,B mapping , C composition,F(*f)(F,F)) : lazytree(s,0,e,op,mapping,composition,f) {}
    lazytree(S(*s)(S,S),int n,S e,A op,B mapping , C composition,F(*f)(F,F)) : lazytree(s,std::vector<S>(n, e),e,op,mapping,composition,f) {}
    lazytree(S(*s)(S,S),const std::vector<S>& v,S e,A op,B mapping , C composition,F(*f)(F,F)) : _n(signed(v.size())),e(e),op(op),mapping(mapping),composition(composition)
     {
        log = ceil_pow2(_n);
        size = 1 << log;
        d = std::vector<S>(2 * size, e);
        lz = std::vector<optional<F>>(size,std::nullopt);
        for (int i = 0; i < _n; i++) d[size + i] = v[i];
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }

    void set(int p, S x) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = x;
        for (int i = 1; i <= log; i++) update(p >> i);
    }

    S get(int p) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        return d[p];
    }

    S prod(int l, int r) {
        assert(0 <= l && l <= r && r <= _n);
        if (l == r) return e;

        l += size;
        r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push(r >> i);
        }

        S sml = e, smr = e;
        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }

        return op(sml, smr);
    }

    S all_prod() { return d[1]; }

    void apply(int p, F f) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = mapping(f, d[p]);
        for (int i = 1; i <= log; i++) update(p >> i);
    }
    void apply(int l, int r, F f) {
        assert(0 <= l && l <= r && r <= _n);
        if (l == r) return;

        l += size;
        r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push((r - 1) >> i);
        }

        for(int l2 = l, r2 = r; l2 < r2; l2 >>= 1, r2 >>= 1){   
            if (l2 & 1) all_apply(l2++, f);
            if (r2 & 1) all_apply(--r2, f);
        }

        for (int i = 1; i <= log; i++) {
            if (((l >> i) << i) != l) update(l >> i);
            if (((r >> i) << i) != r) update((r - 1) >> i);
        }
    }

    template <bool (*g)(S)> int max_right(int l) {
        return max_right(l, [](S x) { return g(x); });
    }
    template <class G> int max_right(int l, G g) {
        assert(0 <= l && l <= _n);
        assert(g(e));
        if (l == _n) return _n;
        l += size;
        for (int i = log; i >= 1; i--) push(l >> i);
        S sm = e;
        do {
            while (l % 2 == 0) l >>= 1;
            if (!g(op(sm, d[l]))) {
                while (l < size) {
                    push(l);
                    l = (2 * l);
                    if (g(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - size;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return _n;
    }

    template <bool (*g)(S)> int min_left(int r) {
        return min_left(r, [](S x) { return g(x); });
    }
    template <class G> int min_left(int r, G g) {
        assert(0 <= r && r <= _n);
        assert(g(e));
        if (r == 0) return 0;
        r += size;
        for (int i = log; i >= 1; i--) push((r - 1) >> i);
        S sm = e;
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!g(op(d[r], sm))) {
                while (r < size) {
                    push(r);
                    r = (2 * r + 1);
                    if (g(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - size;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

  private:
    int _n, size, log;
    std::vector<S> d;
    std::vector<optional<F>> lz;
    A op;
    B mapping;
    C composition;
    S e;
    void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }
    void all_apply(int k, F f) {
      F g=f;
      int k2=k;
      
      while(k2<size){
        F g2=g;
        g=op(g2,g);
        k2*=2;
      
      }
     
        d[k] = mapping(g, d[k]);
        if (k < size) lz[k] =(lz[k] ? composition(f, *lz[k]):f);
    }
    void push(int k) {
        if(lz[k]){
            all_apply(2 * k, *lz[k]);
            all_apply(2 * k + 1, *lz[k]);
            lz[k] = std::nullopt;
        }
    }

};
template <class S,typename A,typename B,typename C>
auto maketree(int n,S a,A b,B c,C d){return lazytree(+b,n,a,b,c,d,+d);}
int n,l[20000],r[2000],q,t[10000],lp[10000],rp[10000],lx[10000],rx[10000];
mint ans[10000]={};
void solve(int x){
  auto tr=maketree(n,make_pair(make_pair((mint)1,(mint)0),make_pair((mint)0,(mint)0)),
  [](ppp a,ppp b)->ppp{
   pair<mint,mint>p,q1,q2;
   p={a.first.first*b.first.first+a.first.second*b.first.second,a.first.first*b.first.second+a.first.second*b.first.first};
   q1={a.second.first*b.first.first+a.second.second*b.first.second,a.second.first*b.first.second+a.second.second*b.first.first};
   q2={a.first.first*b.second.first+a.first.second*b.second.second,a.first.first*b.second.second+a.first.second*b.second.first};
   q1.first+=q2.first;
   q1.second+=q2.second;
   return {p,q1};
  },[](ppp f,ppp a)->ppp{return f;},[](ppp g,ppp f)->ppp{return g;});
  for(int i=0;i<n+q;i++){
    if(i>=n&&t[i-n]==2){
        ans[i-n]+=tr.prod(lp[i-n],rp[i-n]).second.first;
       
        continue;
    }
    int lon,lz,ron,rz;
    if(l[i]&(1ll<<x)){
      lon=((l[i]>>(x+1))<<x)+l[i]%(1ll<<x);
      lz=l[i]-lon;
    }else{
      lz=((l[i]>>(x+1))<<x)+l[i]%(1ll<<x);
      lon=l[i]-lz;
    }
    if(r[i]&(1ll<<x)){
      ron=((r[i]>>(x+1))<<x)+r[i]%(1ll<<x);
      rz=r[i]-ron;
    }else{
      rz=((r[i]>>(x+1))<<x)+r[i]%(1ll<<x);
      ron=r[i]-rz;
    }
    if(i<n)tr.set(i,{make_pair((mint)rz-lz,(mint)ron-lon),make_pair((mint)0,(mint)max(0ll,min(r[i],1ll<<(x+1))-max(l[i],1ll<<x)))});
    else{
      tr.apply(lp[i-n],rp[i-n],{make_pair((mint)rz-lz,(mint)ron-lon),make_pair((mint)0,(mint)max(0ll,min(r[i],1ll<<(x+1))-max(l[i],1ll<<x)))});
         
          
    }

  }
  

}
signed main(){
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  cin>>n;
  for(int i=0;i<n;i++){
    cin>>l[i]>>r[i];
    r[i]++;
  }
  cin>>q;
  for(int i=0;i<q;i++){
    cin>>t[i]>>lp[i]>>rp[i];
    lp[i]--;
    if(t[i]==1){
      cin>>l[i+n]>>r[i+n];
      r[i+n]++;
    }
  }
  for(int i=0;i<30;i++)solve(i);
  for(int i=0;i<q;i++)if(t[i]==2)cout<<ans[i]<<endl;

}
accuracy: 0.2631578947368421
time_ms: 40
memory_kb: 3544
final_rank: 19

code_snippet: //#define NDEBUG
#pragma warning(disable : 4146)

#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <utility>
#include <vector>

namespace n91 {

using i32 = std::int32_t;
using i64 = std::int64_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
using isize = std::ptrdiff_t;
using usize = std::size_t;
using f64 = double;

struct rep {
  struct itr {
    usize i;
    constexpr itr(const usize i) noexcept : i(i) {}
    void operator++() noexcept { ++i; }
    constexpr usize operator*() const noexcept { return i; }
    constexpr bool operator!=(const itr x) const noexcept { return i != x.i; }
  };
  const itr f, l;
  constexpr rep(const usize f, const usize l) noexcept
      : f(std::min(f, l)), l(l) {}
  constexpr auto begin() const noexcept { return f; }
  constexpr auto end() const noexcept { return l; }
};
struct revrep {
  struct itr {
    usize i;
    constexpr itr(const usize i) noexcept : i(i) {}
    void operator++() noexcept { --i; }
    constexpr usize operator*() const noexcept { return i; }
    constexpr bool operator!=(const itr x) const noexcept { return i != x.i; }
  };
  const itr f, l;
  constexpr revrep(const usize f, const usize l) noexcept
      : f(l - 1), l(std::min(f, l) - 1) {}
  constexpr auto begin() const noexcept { return f; }
  constexpr auto end() const noexcept { return l; }
};
template <class T> auto md_vec(const usize n, const T &value) {
  return std::vector<T>(n, value);
}
template <class... Args> auto md_vec(const usize n, Args... args) {
  return std::vector<decltype(md_vec(args...))>(n, md_vec(args...));
}
template <class T> constexpr T difference(const T &a, const T &b) noexcept {
  return a < b ? b - a : a - b;
}
template <class T> void chmin(T &a, const T &b) noexcept {
  if (b < a)
    a = b;
}
template <class T> void chmax(T &a, const T &b) noexcept {
  if (a < b)
    a = b;
}
template <class F> class rec_lambda {
  F f;

public:
  rec_lambda(F &&f_) : f(std::forward<F>(f_)) {}
  template <class... Args> auto operator()(Args &&... args) const {
    return f(*this, std::forward<Args>(args)...);
  }
};
template <class T> T scan() {
  T ret;
  std::cin >> ret;
  return ret;
}
constexpr char eoln = '\n';

i64 floor_div(const i64 n, const i64 d) {
  assert(d != 0);
  return n / d - static_cast<i64>((n ^ d) < 0 && n % d != 0);
}

i64 ceil_div(const i64 n, const i64 d) {
  assert(d != 0);
  return n / d + static_cast<i64>((n ^ d) >= 0 && n % d != 0);
}

#ifdef N91_LOCAL
#define OJ_LOCAL(a, b) b
#else
#define OJ_LOCAL(a, b) a
#endif

} // namespace n91

#pragma GCC target("popcnt")

#include <array>
#include <cstddef>
#include <cstdint>

std::size_t bsf32(const std::uint32_t c) noexcept {
#ifdef __GNUC__
  return __builtin_ctz(c);
#else
  static constexpr std::array<std::uint8_t, 32> table = {
      0,  1, 2,  6,  3,  11, 7,  16, 4,  14, 12, 21, 8,  23, 17, 26,
      31, 5, 10, 15, 13, 20, 22, 25, 30, 9,  19, 24, 29, 18, 28, 27};
  return table[(c & ~c + 1) * 0x4653ADF >> 27 & 0x1F];
#endif
}

std::size_t bsf64(const std::uint64_t c) noexcept {
#ifdef __GNUC__
  return __builtin_ctzll(c);
#else
  static constexpr std::array<std::uint8_t, 64> table = {
      0,  1,  2,  7,  3,  13, 8,  27, 4,  33, 14, 36, 9,  49, 28, 19,
      5,  25, 34, 17, 15, 53, 37, 55, 10, 46, 50, 39, 29, 42, 20, 57,
      63, 6,  12, 26, 32, 35, 48, 18, 24, 16, 52, 54, 45, 38, 41, 56,
      62, 11, 31, 47, 23, 51, 44, 40, 61, 30, 22, 43, 60, 21, 59, 58};
  return table[(c & ~c + 1) * 0x218A7A392DD9ABFULL >> 58 & 0x3F];
#endif
}

std::size_t bsr32(std::uint32_t c) noexcept {
#ifdef __GNUC__
  return 31 - __builtin_clz(c);
#else
  static constexpr std::array<std::uint8_t, 32> table = {
      0,  1, 2,  6,  3,  11, 7,  16, 4,  14, 12, 21, 8,  23, 17, 26,
      31, 5, 10, 15, 13, 20, 22, 25, 30, 9,  19, 24, 29, 18, 28, 27};
  c |= c >> 1;
  c |= c >> 2;
  c |= c >> 4;
  c |= c >> 8;
  c |= c >> 16;
  return table[((c >> 1) + 1) * 0x4653ADF >> 27 & 0x1F];
#endif
}

std::size_t bsr64(std::uint64_t c) noexcept {
#ifdef __GNUC__
  return 63 - __builtin_clzll(c);
#else
  static constexpr std::array<std::uint8_t, 64> table = {
      0,  1,  2,  7,  3,  13, 8,  27, 4,  33, 14, 36, 9,  49, 28, 19,
      5,  25, 34, 17, 15, 53, 37, 55, 10, 46, 50, 39, 29, 42, 20, 57,
      63, 6,  12, 26, 32, 35, 48, 18, 24, 16, 52, 54, 45, 38, 41, 56,
      62, 11, 31, 47, 23, 51, 44, 40, 61, 30, 22, 43, 60, 21, 59, 58};
  c |= c >> 1;
  c |= c >> 2;
  c |= c >> 4;
  c |= c >> 8;
  c |= c >> 16;
  c |= c >> 32;
  return table[((c >> 1) + 1) * 0x218A7A392DD9ABFULL >> 58 & 0x3F];
#endif
}

constexpr std::size_t popcount32(std::uint32_t c) noexcept {
#ifdef __GNUC__
  return __builtin_popcount(c);
#else
  c -= c >> 1 & 0x55555555;
  c = (c & 0x33333333) + (c >> 2 & 0x33333333);
  c = (c + (c >> 4)) & 0x0F0F0F0F;
  return c * 0x01010101 >> 24 & 0x3F;
#endif
}

constexpr std::size_t popcount64(std::uint64_t c) noexcept {
#ifdef __GNUC__
  return __builtin_popcountll(c);
#else
  c -= c >> 1 & 0x5555555555555555;
  c = (c & 0x3333333333333333) + (c >> 2 & 0x3333333333333333);
  c = (c + (c >> 4)) & 0x0F0F0F0F0F0F0F0F;
  return c * 0x0101010101010101 >> 56 & 0x7f;
#endif
}

constexpr bool parity32(std::uint32_t c) noexcept {
#ifdef __GNUC__
  return __builtin_parity(c);
#else
  c ^= c >> 1;
  c ^= c >> 2;
  return ((c & 0x11111111) * 0x11111111 >> 28 & 0x1) != 0;
#endif
}

constexpr bool parity64(std::uint64_t c) noexcept {
#ifdef __GNUC__
  return __builtin_parityll(c);
#else
  c ^= c >> 1;
  c ^= c >> 2;
  return ((c & 0x1111111111111111) * 0x1111111111111111 >> 60 & 0x1) != 0;
#endif
}

#include <array>

#include <cassert>
#include <numeric>
#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#endif


#include <utility>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {

namespace internal {

constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}

struct barrett {
    unsigned int _m;
    unsigned long long im;

    barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}

    unsigned int umod() const { return _m; }

    unsigned int mul(unsigned int a, unsigned int b) const {

        unsigned long long z = a;
        z *= b;
#ifdef _MSC_VER
        unsigned long long x;
        _umul128(z, im, &x);
#else
        unsigned long long x =
            (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
        unsigned int v = (unsigned int)(z - x * _m);
        if (_m <= v) v += _m;
        return v;
    }
};

constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
    if (m == 1) return 0;
    unsigned int _m = (unsigned int)(m);
    unsigned long long r = 1;
    unsigned long long y = safe_mod(x, m);
    while (n) {
        if (n & 1) r = (r * y) % _m;
        y = (y * y) % _m;
        n >>= 1;
    }
    return r;
}

constexpr bool is_prime_constexpr(int n) {
    if (n <= 1) return false;
    if (n == 2 || n == 7 || n == 61) return true;
    if (n % 2 == 0) return false;
    long long d = n - 1;
    while (d % 2 == 0) d /= 2;
    constexpr long long bases[3] = {2, 7, 61};
    for (long long a : bases) {
        long long t = d;
        long long y = pow_mod_constexpr(a, t, n);
        while (t != n - 1 && y != 1 && y != n - 1) {
            y = y * y % n;
            t <<= 1;
        }
        if (y != n - 1 && t % 2 == 0) {
            return false;
        }
    }
    return true;
}
template <int n> constexpr bool is_prime = is_prime_constexpr(n);

constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
    a = safe_mod(a, b);
    if (a == 0) return {b, 0};

    long long s = b, t = a;
    long long m0 = 0, m1 = 1;

    while (t) {
        long long u = s / t;
        s -= t * u;
        m0 -= m1 * u;  // |m1 * u| <= |m1| * s <= b


        auto tmp = s;
        s = t;
        t = tmp;
        tmp = m0;
        m0 = m1;
        m1 = tmp;
    }
    if (m0 < 0) m0 += b / s;
    return {s, m0};
}

constexpr int primitive_root_constexpr(int m) {
    if (m == 2) return 1;
    if (m == 167772161) return 3;
    if (m == 469762049) return 3;
    if (m == 754974721) return 11;
    if (m == 998244353) return 3;
    int divs[20] = {};
    divs[0] = 2;
    int cnt = 1;
    int x = (m - 1) / 2;
    while (x % 2 == 0) x /= 2;
    for (int i = 3; (long long)(i)*i <= x; i += 2) {
        if (x % i == 0) {
            divs[cnt++] = i;
            while (x % i == 0) {
                x /= i;
            }
        }
    }
    if (x > 1) {
        divs[cnt++] = x;
    }
    for (int g = 2;; g++) {
        bool ok = true;
        for (int i = 0; i < cnt; i++) {
            if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                ok = false;
                break;
            }
        }
        if (ok) return g;
    }
}
template <int m> constexpr int primitive_root = primitive_root_constexpr(m);

}  // namespace internal

}  // namespace atcoder


#include <cassert>
#include <numeric>
#include <type_traits>

namespace atcoder {

namespace internal {

#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value ||
                                  std::is_same<T, __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int128 =
    typename std::conditional<std::is_same<T, __uint128_t>::value ||
                                  std::is_same<T, unsigned __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using make_unsigned_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value,
                              __uint128_t,
                              unsigned __int128>;

template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
                                                  is_signed_int128<T>::value ||
                                                  is_unsigned_int128<T>::value,
                                              std::true_type,
                                              std::false_type>::type;

template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                 std::is_signed<T>::value) ||
                                                    is_signed_int128<T>::value,
                                                std::true_type,
                                                std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<(is_integral<T>::value &&
                               std::is_unsigned<T>::value) ||
                                  is_unsigned_int128<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<
    is_signed_int128<T>::value,
    make_unsigned_int128<T>,
    typename std::conditional<std::is_signed<T>::value,
                              std::make_unsigned<T>,
                              std::common_type<T>>::type>::type;

#else

template <class T> using is_integral = typename std::is_integral<T>;

template <class T>
using is_signed_int =
    typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<is_integral<T>::value &&
                                  std::is_unsigned<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
                                              std::make_unsigned<T>,
                                              std::common_type<T>>::type;

#endif

template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;

template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;

template <class T> using to_unsigned_t = typename to_unsigned<T>::type;

}  // namespace internal

}  // namespace atcoder


namespace atcoder {

namespace internal {

struct modint_base {};
struct static_modint_base : modint_base {};

template <class T> using is_modint = std::is_base_of<modint_base, T>;
template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;

}  // namespace internal

template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
struct static_modint : internal::static_modint_base {
    using mint = static_modint;

  public:
    static constexpr int mod() { return m; }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    static_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    static_modint(T v) {
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    static_modint(T v) {
        _v = (unsigned int)(v % umod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        if (prime) {
            assert(_v);
            return pow(umod() - 2);
        } else {
            auto eg = internal::inv_gcd(_v, m);
            assert(eg.first == 1);
            return eg.second;
        }
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
    static constexpr bool prime = internal::is_prime<m>;
};

template <int id> struct dynamic_modint : internal::modint_base {
    using mint = dynamic_modint;

  public:
    static int mod() { return (int)(bt.umod()); }
    static void set_mod(int m) {
        assert(1 <= m);
        bt = internal::barrett(m);
    }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    dynamic_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        long long x = (long long)(v % (long long)(mod()));
        if (x < 0) x += mod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        _v = (unsigned int)(v % mod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        _v = bt.mul(_v, rhs._v);
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        auto eg = internal::inv_gcd(_v, mod());
        assert(eg.first == 1);
        return eg.second;
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static internal::barrett bt;
    static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt = 998244353;

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

namespace internal {

template <class T>
using is_static_modint = std::is_base_of<internal::static_modint_base, T>;

template <class T>
using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}  // namespace internal

}  // namespace atcoder


namespace n91 {

using mint = atcoder::modint998244353;

static constexpr usize BIT = 30;

struct val {
  std::array<std::array<mint, 2>, BIT> free;
  std::array<std::array<mint, 2>, BIT> fixed;
};

using T = val;
T op(const T &l, const T &r) {
  T ret = {};
  for (const usize i : rep(0, BIT)) {
    for (const usize j : rep(0, 2)) {
      for (const usize k : rep(0, 2)) {
        ret.free[i][j ^ k] += l.free[i][j] * r.free[i][k];
        ret.fixed[i][j ^ k] +=
            l.fixed[i][j] * r.free[i][k] + l.free[i][j] * r.fixed[i][k];
      }
    }
  }
  return ret;
}
T id() {
  T ret = {};
  for (const usize i : rep(0, BIT)) {
    ret.free[i][0] = 1;
  }
  return ret;
}

T single(u32 l, u32 r) {
  val ret = {};
  u32 s = 0;
  const auto add = [&](const usize k) {
    for (const usize i : rep(0, s)) {
      ret.free[i][0] += 1 << (s - 1);
      ret.free[i][1] += 1 << (s - 1);
    }
    for (const usize i : rep(s, BIT)) {
      ret.free[i][k >> (i - s) & 1] += 1 << s;
    }
    ret.fixed[bsr32(k) + s][1] += 1 << s;
  };
  while (l != r) {
    if (l & 1) {
      // [l, l+1) << s
      add(l);
      l += 1;
    }
    if (r & 1) {
      r -= 1;
      add(r);
    }
    l >>= 1;
    r >>= 1;
    s += 1;
  }
  return ret;
}

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();
    }
  }
};
} // namespace n91

#include <array>

namespace n91 {

void main_() {
  const usize n = scan<usize>();
  assign_segment_tree seg(n);

  for (const usize i : rep(0, n)) {
    const u32 l = scan<u32>();
    const u32 r = scan<u32>() + 1;
    seg.assign(i, i + 1, single(l, r));
  }

  const usize q = scan<usize>();
  for (const usize i : rep(0, q)) {
    const usize t = scan<usize>();
    if (t == 1) {
      const usize lp = scan<usize>() - 1;
      const usize rp = scan<usize>();
      const u32 l = scan<u32>();
      const u32 r = scan<u32>() + 1;
      seg.assign(lp, rp, single(l, r));
    } else {
      const usize lp = scan<usize>() - 1;
      const usize rp = scan<usize>();
      auto ans = seg.fold(lp, rp);
      mint sum = 0;
      for (const usize i : rep(0, BIT)) {
        sum += ans.fixed[i][0];
      }
      std::cout << sum.val() << eoln;
    }
  }
}

} // namespace n91

int main() {
  //*
  std::ios::sync_with_stdio(false);
  std::cin.tie(nullptr);
  //*/
  std::cout << std::setprecision(20);
  n91::main_();
  return 0;
}
accuracy: 1
time_ms: 330
memory_kb: 34148
final_rank: 9

code_snippet: #include <algorithm>
#include <bitset>
#include <cmath>
#include <complex>
#include <cstdio>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <sys/types.h>
#include <unistd.h>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#pragma region macros
#define _overload(_1, _2, _3, name, ...) name
#define _rep(i, n) _range(i, 0, n)
#define _range(i, a, b) for (int i = int(a); i < int(b); ++i)
#define rep(...) _overload(__VA_ARGS__, _range, _rep, )(__VA_ARGS__)
#define _rrep(i, n) _rrange(i, n, 0)
#define _rrange(i, a, b) for (int i = int(a) - 1; i >= int(b); --i)
#define rrep(...) _overload(__VA_ARGS__, _rrange, _rrep, )(__VA_ARGS__)
#pragma endregion macros

using namespace std;

template <class T> bool chmax(T &a, const T &b) {
    return (a < b) ? (a = b, 1) : 0;
}
template <class T> bool chmin(T &a, const T &b) {
    return (b < a) ? (a = b, 1) : 0;
}

using ll    = long long;
using R     = long double;
const R EPS = 1e-9L;  // [-1000,1000]->EPS=1e-8 [-10000,10000]->EPS=1e-7
inline int sgn(const R &r) {
    return (r > EPS) - (r < -EPS);
}
inline R sq(R x) {
    return sqrt(max(x, 0.0L));
}

const int dx[8] = {1, 0, -1, 0, 1, -1, -1, 1};
const int dy[8] = {0, 1, 0, -1, 1, 1, -1, -1};

const pid_t pid = getpid();
// Problem Specific Parameter:

template <uint32_t MOD> class static_modint
{
  public:
    static_modint(): data(0) {}
    static_modint(int32_t y): data(y >= 0 ? y % MOD : MOD - (-y) % MOD) {}
    static_modint(int64_t y): data(y >= 0 ? y % MOD : MOD - (-y) % MOD) {}

    static static_modint raw(int32_t y) {
        static_modint ret;
        ret.data = y;
        return ret;
    }

    // Arithmetic Oprators
    static_modint &operator+=(const static_modint &that) {
        if ((data += that.data) >= MOD) {
            data -= MOD;
        }
        return *this;
    }
    static_modint &operator-=(const static_modint &that) {
        if ((data += MOD - that.data) >= MOD) {
            data -= MOD;
        }
        return *this;
    }
    static_modint &operator*=(const static_modint &that) {
        data = normalize(1LL * data * that.data);
        return *this;
    }
    static_modint &operator/=(const static_modint &that) {
        return *this *= static_modint(std::get<1>(extgcd(that.data, int(MOD))));
    }
    static_modint &operator%=(const static_modint &that) {
        data %= that.data;
        return *this;
    }

    static_modint &operator+=(const int that) {
        return *this += static_modint(that);
    }
    static_modint &operator-=(const int that) {
        return *this -= static_modint(that);
    }
    static_modint &operator*=(const int that) {
        return *this *= static_modint(that);
    }
    static_modint &operator/=(const int that) {
        return *this /= static_modint(that);
    }
    static_modint &operator%=(const int that) {
        return *this %= static_modint(that);
    }

    // Comparators
    bool operator<(const static_modint &that) {
        return data < that.data;
    }
    bool operator>(const static_modint &that) {
        return data > that.data;
    }
    bool operator<=(const static_modint &that) {
        return data <= that.data;
    }
    bool operator>=(const static_modint &that) {
        return data >= that.data;
    }
    bool operator!=(const static_modint &that) {
        return data != that.data;
    }
    bool operator==(const static_modint &that) {
        return data == that.data;
    }

    // Utilities
    unsigned val() const {
        return data;
    }

    static unsigned mod() {
        return MOD;
    }

    static_modint operator+(const static_modint &that) const {
        return static_modint(*this) += that;
    }
    static_modint operator-(const static_modint &that) const {
        return static_modint(*this) -= that;
    }
    static_modint operator*(const static_modint &that) const {
        return static_modint(*this) *= that;
    }
    static_modint operator/(const static_modint &that) const {
        return static_modint(*this) /= that;
    }
    static_modint operator%(const static_modint &that) const {
        return static_modint(*this) %= that;
    }
    static_modint operator+(const int that) const {
        return static_modint(*this) += that;
    }
    static_modint operator-(const int that) const {
        return static_modint(*this) -= that;
    }
    static_modint operator*(const int that) const {
        return static_modint(*this) *= that;
    }
    static_modint operator/(const int that) const {
        return static_modint(*this) /= that;
    }
    static_modint operator%(const int that) const {
        return static_modint(*this) %= that;
    }
    static_modint operator=(const int that) {
        return *this = static_modint(that);
    }
    friend std::istream &operator>>(std::istream &is, static_modint &that) {
        int64_t tmp;
        is >> tmp;
        that = static_modint(tmp);
        return is;
    }
    friend std::ostream &operator<<(std::ostream &os,
                                    const static_modint &that) {
        return os << that.data;
    }

    static_modint power(ll n) const {
        static_modint b = raw(1), a = *this;
        while (n) {
            if (n & 1) {
                b *= a;
            }
            a *= a;
            n >>= 1;
        }
        return b;
    }

  private:
    unsigned data;

    const static __int128 magic_number = (__int128(1) << 64) / MOD;

    uint64_t normalize(uint64_t x) const {
        const uint64_t q = (x * magic_number) >> 64;
        x -= q * MOD;
        return x < MOD ? x : x - MOD;
    }

    inline std::tuple<int32_t, int32_t, int32_t> extgcd(int32_t a,
                                                        int32_t b) const {
        if (b == 0) {
            return std::make_tuple(a, 1, 0);
        }
        int32_t g, x, y;
        tie(g, x, y) = extgcd(b, a % b);
        std::swap(x, y);
        y -= a / b * x;
        return make_tuple(g, x, y);
    }
};

using modint998244353 = static_modint<998244353>;

template <class S, S (*op)(S, S), S (*e)(), class F, S (*mapping)(F, S),
          F (*composition)(F, F), F (*id)()>
struct lazysegtree {
  public:
    lazysegtree(): lazysegtree(0) {}
    explicit lazysegtree(int n): lazysegtree(std::vector<S>(n, e())) {}
    explicit lazysegtree(const std::vector<S> &value): n(int(value.size())) {
        log  = 32 - __builtin_clz(n);
        size = 1 << log;
        data = std::vector<S>(2 * size, e());
        lazy = std::vector<F>(size, id());
        for (int i = 0; i < n; i++) {
            data[size + i] = value[i];
        }
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }

    void set(int p, S x) {
        p += size;
        for (int i = log; i >= 1; i--) {
            push(p >> i);
        }
        data[p] = x;
        for (int i = 1; i <= log; i++) {
            update(p >> i);
        }
    }

    S get(int p) {
        p += size;
        for (int i = log; i >= 1; i--) {
            push(p >> i);
        }
        return data[p];
    }

    S prod(int l, int r) {
        if (l == r) {
            return e();
        }

        l += size;
        r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) {
                push(l >> i);
            }
            if (((r >> i) << i) != r) {
                push(r >> i);
            }
        }

        S sml = e(), smr = e();
        while (l < r) {
            if (l & 1) {
                sml = op(sml, data[l++]);
            }
            if (r & 1) {
                smr = op(data[--r], smr);
            }
            l >>= 1;
            r >>= 1;
        }

        return op(sml, smr);
    }

    S all_prod() {
        return data[1];
    }

    void apply(int p, F f) {
        p += size;
        for (int i = log; i >= 1; i--) {
            push(p >> i);
        }
        data[p] = mapping(f, data[p]);
        for (int i = 1; i <= log; i++) {
            update(p >> i);
        }
    }
    void apply(int l, int r, F f) {
        if (l == r) {
            return;
        }

        l += size, r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) {
                push(l >> i);
            }
            if (((r >> i) << i) != r) {
                push((r - 1) >> i);
            }
        }

        {
            int l2 = l, r2 = r;
            while (l < r) {
                if (l & 1) {
                    all_apply(l++, f);
                }
                if (r & 1) {
                    all_apply(--r, f);
                }
                l >>= 1, r >>= 1;
            }
            l = l2, r = r2;
        }

        for (int i = 1; i <= log; i++) {
            if (((l >> i) << i) != l) {
                update(l >> i);
            }
            if (((r >> i) << i) != r) {
                update((r - 1) >> i);
            }
        }
    }


  private:
    int n, size, log;
    std::vector<S> data;
    std::vector<F> lazy;

    void update(int k) {
        data[k] = op(data[2 * k], data[2 * k + 1]);
    }
    void all_apply(int k, F f) {
        data[k] = mapping(f, data[k]);
        if (k < size) {
            lazy[k] = composition(f, lazy[k]);
        }
    }
    void push(int k) {
        all_apply(2 * k, lazy[k]);
        all_apply(2 * k + 1, lazy[k]);
        lazy[k] = id();
    }
};

using mint = modint998244353;

using S = struct {
    mint val[4];
    int len;
};

S op(S a, S b) {
    S ret;
    ret.val[0] = a.val[0] * b.val[0] + a.val[1] * b.val[1];
    ret.val[1] = a.val[1] * b.val[0] + a.val[0] * b.val[1];

    ret.val[2] += a.val[0] * b.val[2] + a.val[1] * b.val[3];
    ret.val[2] += a.val[2] * b.val[0] + a.val[3] * b.val[1];

    ret.val[3] += a.val[1] * b.val[2] + a.val[0] * b.val[3];
    ret.val[3] += a.val[2] * b.val[1] + a.val[3] * b.val[0];


    ret.len = a.len + b.len;
    return ret;
}


S e() {
    S ret;
    ret.val[0] = mint(1);
    ret.len    = 0;
    return ret;
}

int get_cnt(int l, int r, int j) {
    const int lo = 1 << j;
    const int hi = lo << 1;

    const int lidx = l / hi;
    const int ridx = r / hi;

    int ret = 0;
    if (lidx == ridx) {
        ret += max(lo, r % hi) - max(lo, l % hi);
    } else {
        ret += hi - max(lo, l % hi);
        ret += max(lo, r % hi) - lo;
        ret += lo * (ridx - lidx - 1);
    }

    return ret;
}

int get_msb(int l, int r, int j) {
    const int lo = 1 << j;
    const int hi = lo << 1;
    return clamp(r, lo, hi) - clamp(l, lo, hi);
}

S create_element(int all, int cnt, int msb) {
    S ret;
    ret.val[0] = mint(all - cnt);
    ret.val[1] = mint(cnt);
    ret.val[2] = mint(0);
    ret.val[3] = mint(msb);
    ret.len    = 1;
    return ret;
}

using F = struct {
    int all;
    int cnt;
    int msb;
};

S mapping(F f, S s) {
    if (f.all == -1) {
        return s;
    }

    S ret = create_element(f.all, f.cnt, f.msb);


    int cur = s.len;
    while (cur > 1) {
        ret = op(ret, ret);
        cur >>= 1;
    }

    return ret;
}

F composition(F f, F fo) {
    if (f.all == -1) {
        return fo;
    }
    return f;
}

F id() {
    return {-1, -1, -1};
}

using segtree_t = lazysegtree<S, op, e, F, mapping, composition, id>;
const int limit = 30;
segtree_t segtrees[limit];


int main(void) {
    std::cin.tie(0);
    std::ios::sync_with_stdio(false);

    int n;
    cin >> n;

    vector<int> init_l(n), init_r(n);

    rep(i, n) {
        cin >> init_l[i] >> init_r[i];
        init_r[i]++;
    }

    rep(j, limit) {
        vector<S> ary;

        rep(i, n) {
            const int l = init_l[i];
            const int r = init_r[i];

            const int all = r - l;
            const int cnt = get_cnt(l, r, j);
            const int msb = get_msb(l, r, j);
            ary.push_back(create_element(all, cnt, msb));
        }

        segtrees[j] = segtree_t(ary);
    }


    int q;
    cin >> q;

    rep(loop, q) {
        int k;
        cin >> k;
        if (k == 1) {
            int lp, rp, l, r;
            cin >> lp >> rp >> l >> r;
            lp--, r++;

            rep(j, limit) {
                const int all = r - l;
                const int cnt = get_cnt(l, r, j);
                const int msb = get_msb(l, r, j);
                segtrees[j].apply(lp, rp, {all, cnt, msb});
            }
        } else {
            int lp, rp;
            cin >> lp >> rp;
            lp--;
            mint ans;
            rep(j, limit) {
                const mint val = segtrees[j].prod(lp, rp).val[2];
                ans += val;
            }
            cout << ans.val() << endl;
        }
    }

    return 0;
}
accuracy: 1
time_ms: 1360
memory_kb: 28636
final_rank: 14

code_snippet: #include "iostream"
#include "climits"
#include "list"
#include "queue"
#include "stack"
#include "set"
#include "functional"
#include "algorithm"
#include "string"
#include "map"
#include "unordered_map"
#include "unordered_set"
#include "iomanip"
#include "cmath"
#include "random"
#include "bitset"
#include "cstdio"
#include "numeric"
#include "cassert"
#include "ctime"

using namespace std;

constexpr long long MOD = 998244353;
constexpr int BIT = 30;

int N, K;

struct onoff {
	long long on, off;
	onoff(const long long off = 1, const long long on = 0) :off(off), on(on) {

	}
	onoff operator % (const long long mod)const {
		return onoff(off % MOD, on % MOD);
	}
	void operator %= (const long long mod) {
		off %= MOD;
		on %= MOD;
	}
	onoff operator + (const onoff& o)const {
		return onoff(off + o.off, on + o.on) % MOD;
	}
	void operator += (const onoff& o) {
		off += o.off;
		if (off >= MOD)off -= MOD;
		on += o.on;
		if (on >= MOD)on -= MOD;
	}
	onoff operator * (const onoff& o)const {
		return onoff(off * o.off + on * o.on, off * o.on + on * o.off) % MOD;
	}
	onoff operator *(const long long& v)const {
		return onoff(off * v, on * v) % MOD;
	}
	void operator *= (const onoff& o) {
		long long tmp = off;
		off = on * o.on + off * o.off;
		off %= MOD;
		on = tmp * o.on + on * o.off;
		on %= MOD;
	}
	void operator *= (const long long& by) {
		on *= by;
		on %= MOD;
		off *= by;
		off %= MOD;
	}
	void Output() {
		cout << "off = " << off << " on = " << on << endl;
	}
};

struct Node {
	onoff by, sum;
	Node(onoff by = onoff(), onoff sum = onoff(0, 0)) :by(by), sum(sum) {

	}
	Node operator *(const Node& n)const {
		return Node(by * n.by, sum * n.by + by * n.sum);
	}
	void  operator *=(const Node& n) {
		sum = sum * n.by + by * n.sum;
		by *= n.by;
	}
};

Node power(Node v, int m) {
	if (m == 1)return v;
	return power(v * v, m - 1);
}

class SegmentTree {
	int sz;
	vector<Node>v;
	vector<int>l;
	vector<int>r;
	vector<int>depth;
	vector<int>flag;
	vector<Node>base;
	Node ret;
	void Left(int place) {
		if (place >= sz / 2) {
			l[place] = place - sz / 2;
			depth[place] = 1;
			return;
		}
		Left(place * 2);
		Left(place * 2 + 1);
		l[place] = l[place * 2];
		depth[place] = depth[place * 2] + 1;
		return;
	}
	void Right(int place) {
		if (place >= sz / 2) {
			r[place] = place - sz / 2;
			return;
		}
		Right(place * 2);
		Right(place * 2 + 1);
		r[place] = r[place * 2 + 1];
		return;
	}
	void Sum(int p) {
		if (p >= sz / 2) {

		}
		else {
			v[p] = v[p * 2] * v[p * 2 + 1];
		}
	}
	void Collect(int p) {
		v[p] = v[p * 2] * v[p * 2 + 1];
	}
	void Spread(int p) {
		if (flag[p]) {
			flag[p] = 0;
			flag[p * 2] = 1;
			flag[p * 2 + 1] = 1;
			base[p * 2] = base[p * 2 + 1] = base[p];
			v[p * 2] = v[p * 2 + 1] = power(base[p * 2], depth[p * 2]);
		}
	}
	void Sum(int L, int R, int p) {
		if (R < l[p] || r[p] < L)return;
		if (L <= l[p] && r[p] <= R) {
			ret *= v[p];
			return;
		}
		Spread(p);
		Sum(L, R, p * 2);
		Sum(L, R, p * 2 + 1);
		Collect(p);
	}
public:
	SegmentTree(int n) {
		n++;
		sz = 1;
		while (sz * 2 < n * 4)sz <<= 1;
		v.resize(sz);
		l.resize(sz);
		r.resize(sz);
		flag.resize(sz);
		base.resize(sz);
		depth.resize(sz);
		Left(1);
		Right(1);
		for (int i = sz / 2; i < sz; i++) {
			v[i].sum = onoff(0, 0);
		}
		for (int i = sz / 2; i > 0; i--) {
			Sum(i);
		}
	}
	long long Sum(int L, int R) {
		ret = Node();
		Sum(L, R, 1);
		return ret.sum.off;
	}
	void Insert(int p, onoff num, onoff mxnum) {
		p += sz / 2;
		v[p].by = num;
		v[p].sum = mxnum;
		p >>= 1;
		while (p) {
			Sum(p);
			p >>= 1;
		}
	}
	void Insert(int L, int R, onoff num, onoff mxnum, int p = 1) {
		if (R < l[p] || r[p] < L)return;
		if (L <= l[p] && r[p] <= R) {
			base[p] = Node(num, mxnum);
			flag[p] = 1;
			v[p] = power(base[p], depth[p]);
			return;
		}
		Spread(p);
		Insert(L, R, num, mxnum, p * 2);
		Insert(L, R, num, mxnum, p * 2 + 1);
		Collect(p);
	}
	void Debug() {
		cout << "sz = " << sz << endl;
	}
};


vector<onoff>func1(long long L, long long R) {
	vector<onoff>ret(BIT);
	long long by = 1;
	for (int j = 0; j < BIT; j++) {
		ret[j] = onoff(0, 0);
		by <<= 1;
		long long st = L / by;
		long long ed = R / by;
		ret[j].on += max(ed - st - 1, 0LL) * (by / 2);
		if (st < ed) {
			ret[j].on += max(0LL, R % by - by / 2 + 1);
			ret[j].on += min(by / 2, by - L % by);
		}
		else {
			ret[j].on += max(0LL, R % by - by / 2 + 1);
			if (L % by) {
				ret[j].on -= max(0LL, (L - 1) % by - by / 2 + 1);
			}
		}
		ret[j].on %= MOD;
	}
	for (int i = 0; i < BIT; i++) {
		ret[i].off = R - L + 1 - ret[i].on;
		ret[i].off %= MOD;
	}
	return ret;
}

vector<onoff>func2(long long L, long long R) {
	vector<onoff>ret(BIT);
	for (int j = 0; j < BIT; j++) {
		ret[j] = onoff(0, 0);
		ret[j].on = max(0LL, min((1LL << (j + 1)) - 1, R) - max(1LL << j, L) + 1);
		ret[j].on %= MOD;
	}
	return ret;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);

	cin >> N;
	vector<int>l(N);
	vector<int>r(N);
	vector<vector<onoff>>num(N, vector<onoff>(BIT));
	vector<vector<onoff>>mxnum(N, vector<onoff>(BIT));
	for (int i = 0; i < N; i++) {
		cin >> l[i] >> r[i];
		num[i] = func1(l[i], r[i]);
		mxnum[i] = func2(l[i], r[i]);
	}
	vector<SegmentTree>sg(BIT, SegmentTree(N));
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < BIT; j++) {
			sg[j].Insert(i, i, num[i][j], mxnum[i][j]);
		}
	}
	cin >> K;
	for (int turn = 0; turn < K; turn++) {
		int a;
		cin >> a;
		if (a == 1) {
			int lp, rp, L, R;
			cin >> lp >> rp >> L >> R;
			lp--, rp--;
			auto boxnum = func1(L, R);
			auto boxmxnum = func2(L, R);
			for (int i = 0; i < BIT; i++) {
				sg[i].Insert(lp, rp, boxnum[i], boxmxnum[i]);
			}
		}
		else {
			int L, R;
			cin >> L >> R;
			L--, R--;
			long long ans = 0;
			for (int i = 0; i < BIT; i++) {
				ans += sg[i].Sum(L, R);
			}
			cout << ans % MOD << endl;
		}
	}
}
accuracy: 1
time_ms: 690
memory_kb: 93412
final_rank: 13

code_snippet: #include <algorithm>
#include <bitset>
#include <cmath>
#include <complex>
#include <cstdio>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <sys/types.h>
#include <unistd.h>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#pragma region macros
#define _overload(_1, _2, _3, name, ...) name
#define _rep(i, n) _range(i, 0, n)
#define _range(i, a, b) for (int i = int(a); i < int(b); ++i)
#define rep(...) _overload(__VA_ARGS__, _range, _rep, )(__VA_ARGS__)
#define _rrep(i, n) _rrange(i, n, 0)
#define _rrange(i, a, b) for (int i = int(a) - 1; i >= int(b); --i)
#define rrep(...) _overload(__VA_ARGS__, _rrange, _rrep, )(__VA_ARGS__)
#pragma endregion macros

using namespace std;

template <class T> bool chmax(T &a, const T &b) {
    return (a < b) ? (a = b, 1) : 0;
}
template <class T> bool chmin(T &a, const T &b) {
    return (b < a) ? (a = b, 1) : 0;
}

using ll    = long long;
using R     = long double;
const R EPS = 1e-9L;  // [-1000,1000]->EPS=1e-8 [-10000,10000]->EPS=1e-7
inline int sgn(const R &r) {
    return (r > EPS) - (r < -EPS);
}
inline R sq(R x) {
    return sqrt(max(x, 0.0L));
}

const int dx[8] = {1, 0, -1, 0, 1, -1, -1, 1};
const int dy[8] = {0, 1, 0, -1, 1, 1, -1, -1};

const pid_t pid = getpid();
// Problem Specific Parameter:

template <uint32_t MOD> class static_modint
{
  public:
    static_modint(): data(0) {}
    static_modint(int32_t y): data(y >= 0 ? y % MOD : MOD - (-y) % MOD) {}
    static_modint(int64_t y): data(y >= 0 ? y % MOD : MOD - (-y) % MOD) {}

    static static_modint raw(int32_t y) {
        static_modint ret;
        ret.data = y;
        return ret;
    }

    // Arithmetic Oprators
    static_modint &operator+=(const static_modint &that) {
        if ((data += that.data) >= MOD) {
            data -= MOD;
        }
        return *this;
    }
    static_modint &operator-=(const static_modint &that) {
        if ((data += MOD - that.data) >= MOD) {
            data -= MOD;
        }
        return *this;
    }
    static_modint &operator*=(const static_modint &that) {
        data = normalize(1LL * data * that.data);
        return *this;
    }
    static_modint &operator/=(const static_modint &that) {
        return *this *= static_modint(std::get<1>(extgcd(that.data, int(MOD))));
    }
    static_modint &operator%=(const static_modint &that) {
        data %= that.data;
        return *this;
    }

    static_modint &operator+=(const int that) {
        return *this += static_modint(that);
    }
    static_modint &operator-=(const int that) {
        return *this -= static_modint(that);
    }
    static_modint &operator*=(const int that) {
        return *this *= static_modint(that);
    }
    static_modint &operator/=(const int that) {
        return *this /= static_modint(that);
    }
    static_modint &operator%=(const int that) {
        return *this %= static_modint(that);
    }

    // Comparators
    bool operator<(const static_modint &that) {
        return data < that.data;
    }
    bool operator>(const static_modint &that) {
        return data > that.data;
    }
    bool operator<=(const static_modint &that) {
        return data <= that.data;
    }
    bool operator>=(const static_modint &that) {
        return data >= that.data;
    }
    bool operator!=(const static_modint &that) {
        return data != that.data;
    }
    bool operator==(const static_modint &that) {
        return data == that.data;
    }

    // Utilities
    unsigned val() const {
        return data;
    }

    static unsigned mod() {
        return MOD;
    }

    static_modint operator+(const static_modint &that) const {
        return static_modint(*this) += that;
    }
    static_modint operator-(const static_modint &that) const {
        return static_modint(*this) -= that;
    }
    static_modint operator*(const static_modint &that) const {
        return static_modint(*this) *= that;
    }
    static_modint operator/(const static_modint &that) const {
        return static_modint(*this) /= that;
    }
    static_modint operator%(const static_modint &that) const {
        return static_modint(*this) %= that;
    }
    static_modint operator+(const int that) const {
        return static_modint(*this) += that;
    }
    static_modint operator-(const int that) const {
        return static_modint(*this) -= that;
    }
    static_modint operator*(const int that) const {
        return static_modint(*this) *= that;
    }
    static_modint operator/(const int that) const {
        return static_modint(*this) /= that;
    }
    static_modint operator%(const int that) const {
        return static_modint(*this) %= that;
    }
    static_modint operator=(const int that) {
        return *this = static_modint(that);
    }
    friend std::istream &operator>>(std::istream &is, static_modint &that) {
        int64_t tmp;
        is >> tmp;
        that = static_modint(tmp);
        return is;
    }
    friend std::ostream &operator<<(std::ostream &os,
                                    const static_modint &that) {
        return os << that.data;
    }

    static_modint power(ll n) const {
        static_modint b = raw(1), a = *this;
        while (n) {
            if (n & 1) {
                b *= a;
            }
            a *= a;
            n >>= 1;
        }
        return b;
    }

  private:
    unsigned data;

    const static __int128 magic_number = (__int128(1) << 64) / MOD;

    uint64_t normalize(uint64_t x) const {
        const uint64_t q = (x * magic_number) >> 64;
        x -= q * MOD;
        return x < MOD ? x : x - MOD;
    }

    inline std::tuple<int32_t, int32_t, int32_t> extgcd(int32_t a,
                                                        int32_t b) const {
        if (b == 0) {
            return std::make_tuple(a, 1, 0);
        }
        int32_t g, x, y;
        tie(g, x, y) = extgcd(b, a % b);
        std::swap(x, y);
        y -= a / b * x;
        return make_tuple(g, x, y);
    }
};

using modint998244353 = static_modint<998244353>;

template <class S, S (*op)(S, S), S (*e)()> struct segtree {
  public:
    segtree(): segtree(0) {}
    explicit segtree(int n): segtree(std::vector<S>(n, e())) {}
    explicit segtree(const std::vector<S> &value): n(int(value.size())) {
        log  = 32 - __builtin_clz(n);
        size = 1 << log;
        data = std::vector<S>(2 * size, e());
        for (int i = 0; i < n; i++) {
            data[size + i] = value[i];
        }
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }

    void set(int p, S x) {
        p += size;
        data[p] = x;
        for (int i = 1; i <= log; i++) {
            update(p >> i);
        }
    }

    S get(int p) {
        return data[p + size];
    }

    S prod(int l, int r) {
        S sml = e(), smr = e();

        for (l += size, r += size; l < r; l >>= 1, r >>= 1) {
            if (l & 1) {
                sml = op(sml, data[l++]);
            }
            if (r & 1) {
                smr = op(data[--r], smr);
            }
        }

        return op(sml, smr);
    }

    S all_prod() {
        return data[1];
    }

  private:
    int n, size, log;
    std::vector<S> data;

    void update(int k) {
        data[k] = op(data[2 * k], data[2 * k + 1]);
    }
};

template <class S, S (*e)()> struct matrix {
  public:
    matrix(): matrix(0) {}
    explicit matrix(size_t n): matrix(n, n) {}
    explicit matrix(size_t n, size_t m):
        matrix(std::vector<std::vector<S>>(n, std::vector<S>(m))) {}
    explicit matrix(const std::vector<std::vector<S>> &ary): data(ary) {}

    ~matrix() = default;

    static matrix identity_matrix(size_t n) {
        matrix ret(n);
        for (size_t i = 0; i < n; ++i) {
            ret[i][i] = e();
        }
        return ret;
    }

    decltype(auto) row() const {
        return data.size();
    }
    decltype(auto) col() const {
        return row() == 0 ? 0 : data[0].size();
    }
    decltype(auto) size() const {
        return row() * col();
    }
    decltype(auto) empty() const {
        return row() == 0;
    }

    decltype(auto) begin() {
        return begin(data);
    }
    decltype(auto) end() {
        return end(data);
    }
    decltype(auto) begin() const {
        return begin(data);
    }
    decltype(auto) end() const {
        return end(data);
    }

    std::vector<S> &operator[](std::size_t pos) {
        return data[pos];
    }
    const std::vector<S> &operator[](std::size_t pos) const {
        return data[pos];
    }

    friend std::ostream &operator<<(std::ostream &os, const matrix &that) {
        for (size_t i = 0; i < that.row(); ++i) {
            for (size_t j = 0; j < that.col(); ++j) {
                os << (j > 0 ? " " : "") << that.data[i][j];
            }

            if (i < that.row()) {
                os << std::endl;
            }
        }

        return os;
    }

    matrix &operator=(const matrix &that) {
        data = that.data;
        return *this;
    }

    //     // Arithmetic Oprators
    matrix &operator+=(const matrix &that) {
        const size_t n = row(), m = col();
        for (size_t i = 0; i < n; ++i) {
            for (size_t j = 0; j < m; ++j) {
                data[i][j] += that.data[i][j];
            }
        }
        return *this;
    }

    matrix &operator-=(const matrix &that) {
        const size_t n = row(), m = col();
        for (size_t i = 0; i < n; ++i) {
            for (size_t j = 0; j < m; ++j) {
                data[i][j] -= that.data[i][j];
            }
        }
        return *this;
    }

    matrix &operator*=(const matrix &that) {
        const size_t n = row(), m = col(), k = that.col();
        matrix res(n, k);
        for (size_t a = 0; a < n; ++a) {
            for (size_t b = 0; b < m; ++b) {
                for (size_t c = 0; c < k; ++c) {
                    res[a][c] += data[a][b] * that[b][c];
                }
            }
        }
        this->operator=(res);
        return *this;
    }

    friend matrix operator+(const matrix &lhs, const matrix &rhs) {
        return matrix(lhs) += rhs;
    }

    friend matrix operator-(const matrix &lhs, const matrix &rhs) {
        return matrix(lhs) -= rhs;
    }

    friend matrix operator*(const matrix &lhs, const matrix &rhs) {
        return matrix(lhs) *= rhs;
    }

    matrix power(ll k) {
        const size_t n = row();
        matrix res     = identity_matrix(n);
        matrix a       = *this;

        while (k > 0) {
            if (k & 1) {
                res *= a;
            }
            a *= a;
            k >>= 1;
        }

        return res;
    }

  private:
    std::vector<std::vector<S>> data;
};

using mint = modint998244353;

mint e_mint() {
    return mint::raw(1);
}

using mat = matrix<mint, e_mint>;

using S = mat;

S op(S a, S b) {
    return a * b;
}

S e() {
    return mat::identity_matrix(4);
}

const int amax = 1000010;

int get_cnt(int l, int r, int j) {
    const int lo = 1 << j;
    const int hi = lo << 1;

    const int lidx = l / hi;
    const int ridx = r / hi;

    int ret = 0;
    if (lidx == ridx) {
        ret += max(lo, r % hi) - max(lo, l % hi);
    } else {
        ret += hi - max(lo, l % hi);
        ret += max(lo, r % hi) - lo;
        ret += lo * (ridx - lidx - 1);
    }

    return ret;
}

int get_msb(int l, int r, int j) {
    const int lo = 1 << j;
    const int hi = lo << 1;
    return clamp(r, lo, hi) - clamp(l, lo, hi);
}

S get_element(int l, int r, int j) {
    const int all = r - l;
    const int cnt = get_cnt(l, r, j);
    const int msb = get_msb(l, r, j);

    S ret;

    ret = mat(4);

    ret[0][0] = mint::raw(all - cnt);
    ret[0][1] = mint::raw(cnt);
    ret[1][0] = mint::raw(cnt);
    ret[1][1] = mint::raw(all - cnt);


    ret[2][0] = mint::raw(0);
    ret[2][1] = mint::raw(msb);
    ret[2][2] = mint::raw(all - cnt);
    ret[2][3] = mint::raw(cnt);


    ret[3][0] = mint::raw(msb);
    ret[3][1] = mint::raw(0);
    ret[3][2] = mint::raw(cnt);
    ret[3][3] = mint::raw(all - cnt);

    return ret;
}

using segtree_t = segtree<S, op, e>;
const int limit = 20;
segtree_t segtrees[limit];


int main(void) {
    std::cin.tie(0);
    std::ios::sync_with_stdio(false);

    int n;
    cin >> n;

    vector<vector<S>> ary(limit);


    rep(i, n) {
        int l, r;
        cin >> l >> r;
        r++;

        rep(j, limit) {
            ary[j].push_back(get_element(l, r, j));
        }
    }

    rep(j, limit) {
        segtrees[j] = segtree_t(ary[j]);
    }

    int q;
    cin >> q;

    rep(loop, q) {
        int k;
        cin >> k;
        if (k == 1) {
            int p, l, r;
            cin >> p >> l >> r;
            p--, r++;

            rep(j, limit) {
                ary[j][p] = get_element(l, r, j);
                segtrees[j].set(p, get_element(l, r, j));
            }
        } else {
            mint ans;
            rep(j, limit) {
                const mint val = segtrees[j].all_prod()[2][0];
                ans += val;
            }
            cout << ans.val() << endl;
        }
    }

    return 0;
}
accuracy: 1
time_ms: 380
memory_kb: 61168
final_rank: 10

code_snippet: #include "iostream"
#include "climits"
#include "list"
#include "queue"
#include "stack"
#include "set"
#include "functional"
#include "algorithm"
#include "string"
#include "map"
#include "unordered_map"
#include "unordered_set"
#include "iomanip"
#include "cmath"
#include "random"
#include "bitset"
#include "cstdio"
#include "numeric"
#include "cassert"
#include "ctime"

using namespace std;

constexpr long long MOD = 998244353;
constexpr int BIT = 20;

int N, K;

struct onoff {
	long long on, off;
	onoff(const long long off = 1, const long long on = 0) :off(off), on(on) {

	}
	onoff operator % (const long long mod)const {
		return onoff(off % MOD, on % MOD);
	}
	void operator %= (const long long mod) {
		off %= MOD;
		on %= MOD;
	}
	onoff operator + (const onoff& o)const {
		return onoff(off + o.off, on + o.on) % MOD;
	}
	void operator += (const onoff& o) {
		off += o.off;
		if (off >= MOD)off -= MOD;
		on += o.on;
		if (on >= MOD)on -= MOD;
	}
	onoff operator * (const onoff& o)const {
		return onoff(off * o.off + on * o.on, off * o.on + on * o.off) % MOD;
	}
	onoff operator *(const long long& v)const {
		return onoff(off * v, on * v) % MOD;
	}
	void operator *= (const onoff& o) {
		long long tmp = off;
		off = on * o.on + off * o.off;
		off %= MOD;
		on = tmp * o.on + on * o.off;
		on %= MOD;
	}
	void operator *= (const long long& by) {
		on *= by;
		on %= MOD;
		off *= by;
		off %= MOD;
	}
	void Output() {
		cout << "off = " << off << " on = " << on << endl;
	}
};

class SegmentTree {
	int sz;
	vector<onoff>by;
	vector<onoff>sum;
	vector<int>l;
	vector<int>r;
	onoff retsum;
	onoff retby;
	void Left(int place) {
		if (place >= sz / 2) {
			l[place] = place - sz / 2;
			return;
		}
		Left(place * 2);
		Left(place * 2 + 1);
		l[place] = l[place * 2];
		return;
	}
	void Right(int place) {
		if (place >= sz / 2) {
			r[place] = place - sz / 2;
			return;
		}
		Right(place * 2);
		Right(place * 2 + 1);
		r[place] = r[place * 2 + 1];
		return;
	}
	void Sum(int p) {
		if (p >= sz / 2) {
			
		}
		else {
			by[p] = by[p * 2] * by[p * 2 + 1];
			sum[p] = sum[p * 2] * by[p * 2 + 1];
			sum[p] += by[p * 2] * sum[p * 2 + 1];
		}
	}
	void Sum(int L, int R, int p) {
		if (R < l[p] || r[p] < L)return;
		if (L <= l[p] && r[p] <= R) {
			retsum = retsum * by[p] + retby * sum[p];
			retby *= by[p];
			return;
		}
		Sum(L, R, p * 2);
		Sum(L, R, p * 2 + 1);
	}
public:
	SegmentTree(int n) {
		n++;
		sz = 1;
		while (sz * 2 < n * 4)sz <<= 1;
		sum.resize(sz);
		by.resize(sz);
		l.resize(sz);
		r.resize(sz);
		Left(1);
		Right(1);
		for (int i = sz / 2; i < sz; i++) {
			sum[i] = onoff(0, 0);
		}
		for (int i = sz / 2; i > 0; i--) {
			Sum(i);
		}
	}
	long long Accumulate() {
		return sum[1].off;
	}
	long long Sum(int L, int R) {
		retsum = onoff(0,0);
		retby = onoff();
		Sum(L, R, 1);
		return retsum.off;
	}
	void Insert(int p, onoff num, onoff mxnum) {
		p += sz / 2;
		by[p] = num;
		sum[p] = mxnum;
		p >>= 1;
		while (p) {
			Sum(p);
			p >>= 1;
		}
	}
	void Debug() {
		cout << "sz = " << sz << endl;
	}
};


vector<onoff>func1(long long L, long long R) {
	vector<onoff>ret(BIT);
	long long by = 1;
	for (int j = 0; j < BIT; j++) {
		ret[j] = onoff(0, 0);
		by <<= 1;
		long long st = L / by;
		long long ed = R / by;
		ret[j].on += max(ed - st - 1, 0LL) * (by / 2);
		if (st < ed) {
			ret[j].on += max(0LL, R % by - by / 2 + 1);
			ret[j].on += min(by / 2, by - L % by);
		}
		else {
			ret[j].on += max(0LL, R % by - by / 2 + 1);
			if (L % by) {
				ret[j].on -= max(0LL, (L - 1) % by - by / 2 + 1);
			}
		}
		ret[j].on %= MOD;
	}
	for (int i = 0; i < BIT; i++) {
		ret[i].off = R - L + 1 - ret[i].on;
		ret[i].off %= MOD;
	}
	return ret;
}

vector<onoff>func2(long long L, long long R) {
	vector<onoff>ret(BIT);
	for (int j = 0; j < BIT; j++) {
		ret[j] = onoff(0, 0);
		ret[j].on = max(0LL, min((1LL << (j + 1)) - 1, R) - max(1LL << j, L) + 1);
		ret[j].on %= MOD;
	}
	return ret;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);

	cin >> N;
	vector<int>l(N);
	vector<int>r(N);
	vector<vector<onoff>>num(N, vector<onoff>(BIT));
	vector<vector<onoff>>mxnum(N, vector<onoff>(BIT));
	for (int i = 0; i < N; i++) {
		cin >> l[i] >> r[i];
		num[i] = func1(l[i], r[i]);
		mxnum[i] = func2(l[i], r[i]);
	}
	vector<SegmentTree>sg(BIT, SegmentTree(N));
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < BIT; j++) {
			sg[j].Insert(i, num[i][j], mxnum[i][j]);
		}
	}
	cin >> K;
	while (K--) {
		int a;
		cin >> a;
		if (a == 1) {
			int p, L, R;
			cin >> p >> L >> R;
			p--;
			l[p] = L;
			r[p] = R;
			num[p] = func1(l[p], r[p]);
			mxnum[p] = func2(l[p], r[p]);
			for (int i = 0; i < BIT; i++) {
				sg[i].Insert(p, num[p][i], mxnum[p][i]);
			}
		}
		else {
			long long ans = 0;
			for (int i = 0; i < BIT; i++) {
				ans += sg[i].Sum(0, N - 1);
			}
			cout << ans % MOD << endl;
		}
	}
}
accuracy: 1
time_ms: 20
memory_kb: 12120
final_rank: 4

code_snippet: #include "iostream"
#include "climits"
#include "list"
#include "queue"
#include "stack"
#include "set"
#include "functional"
#include "algorithm"
#include "string"
#include "map"
#include "unordered_map"
#include "unordered_set"
#include "iomanip"
#include "cmath"
#include "random"
#include "bitset"
#include "cstdio"
#include "numeric"
#include "cassert"
#include "ctime"

using namespace std;

constexpr long long MOD = 998244353;
constexpr int BIT = 20;

int N, K;

struct onoff {
	long long on, off;
	onoff(const long long off = 1, const long long on = 0) :off(off), on(on) {

	}
	onoff operator % (const long long mod)const {
		return onoff(off % MOD, on % MOD);
	}
	void operator %= (const long long mod) {
		off %= MOD;
		on %= MOD;
	}
	onoff operator + (const onoff& o)const {
		return onoff(off + o.off, on + o.on) % MOD;
	}
	void operator += (const onoff& o) {
		off += o.off;
		if (off >= MOD)off -= MOD;
		on += o.on;
		if (on >= MOD)on -= MOD;
	}
	onoff operator * (const onoff& o)const {
		return onoff(off * o.off + on * o.on, off * o.on + on * o.off) % MOD;
	}
	onoff operator *(const long long& v)const {
		return onoff(off * v, on * v) % MOD;
	}
	void operator *= (const onoff& o) {
		long long tmp = off;
		off = on * o.on + off * o.off;
		off %= MOD;
		on = tmp * o.on + on * o.off;
		on %= MOD;
	}
	void operator *= (const long long& by) {
		on *= by;
		on %= MOD;
		off *= by;
		off %= MOD;
	}
	void Output() {
		cout << "off = " << off << " on = " << on << endl;
	}
};

class SegmentTree {
	int sz;
	vector<onoff>by;
	vector<onoff>sum;
	vector<int>l;
	vector<int>r;
	void Left(int place) {
		if (place >= sz / 2) {
			l[place] = place - sz / 2;
			return;
		}
		Left(place * 2);
		Left(place * 2 + 1);
		l[place] = l[place * 2];
		return;
	}
	void Right(int place) {
		if (place >= sz / 2) {
			r[place] = place - sz / 2;
			return;
		}
		Right(place * 2);
		Right(place * 2 + 1);
		r[place] = r[place * 2 + 1];
		return;
	}
	void Sum(int p) {
		if (p >= sz / 2) {
			
		}
		else {
			by[p] = by[p * 2] * by[p * 2 + 1];
			sum[p] = sum[p * 2] * by[p * 2 + 1];
			sum[p] += by[p * 2] * sum[p * 2 + 1];
		}
	}
	
public:
	SegmentTree(int n) {
		n++;
		sz = 1;
		while (sz * 2 < n * 4)sz <<= 1;
		sum.resize(sz);
		by.resize(sz);
		l.resize(sz);
		r.resize(sz);
		Left(1);
		Right(1);
		for (int i = sz / 2; i < sz; i++) {
			sum[i] = onoff(0, 0);
		}
		for (int i = sz / 2; i > 0; i--) {
			Sum(i);
		}
	}
	long long Accumulate() {
		return sum[1].off;
	}
	void Insert(int p, onoff num, onoff mxnum) {
		p += sz / 2;
		by[p] = num;
		sum[p] = mxnum;
		p >>= 1;
		while (p) {
			Sum(p);
			p >>= 1;
		}
	}
	void Debug() {
		cout << "sz = " << sz << endl;
	}
};


vector<onoff>func1(long long L, long long R) {
	vector<onoff>ret(BIT);
	long long by = 1;
	for (int j = 0; j < BIT; j++) {
		ret[j] = onoff(0, 0);
		by <<= 1;
		long long st = L / by;
		long long ed = R / by;
		ret[j].on += max(ed - st - 1, 0LL) * (by / 2);
		if (st < ed) {
			ret[j].on += max(0LL, R % by - by / 2 + 1);
			ret[j].on += min(by / 2, by - L % by);
		}
		else {
			ret[j].on += max(0LL, R % by - by / 2 + 1);
			if (L % by) {
				ret[j].on -= max(0LL, (L - 1) % by - by / 2 + 1);
			}
		}
		ret[j].on %= MOD;
	}
	for (int i = 0; i < BIT; i++) {
		ret[i].off = R - L + 1 - ret[i].on;
		ret[i].off %= MOD;
	}
	return ret;
}

vector<onoff>func2(long long L, long long R) {
	vector<onoff>ret(BIT);
	for (int j = 0; j < BIT; j++) {
		ret[j] = onoff(0, 0);
		ret[j].on = max(0LL, min((1LL << (j + 1)) - 1, R) - max(1LL << j, L) + 1);
		ret[j].on %= MOD;
	}
	return ret;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);

	cin >> N;
	vector<int>l(N);
	vector<int>r(N);
	vector<vector<onoff>>num(N, vector<onoff>(BIT));
	vector<vector<onoff>>mxnum(N, vector<onoff>(BIT));
	for (int i = 0; i < N; i++) {
		cin >> l[i] >> r[i];
		num[i] = func1(l[i], r[i]);
		mxnum[i] = func2(l[i], r[i]);
	}
	vector<SegmentTree>sg(BIT, SegmentTree(N));
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < BIT; j++) {
			sg[j].Insert(i, num[i][j], mxnum[i][j]);
		}
	}
	cin >> K;
	while (K--) {
		int a;
		cin >> a;
		if (a == 1) {
			int p, L, R;
			cin >> p >> L >> R;
			p--;
			l[p] = L;
			r[p] = R;
			num[p] = func1(l[p], r[p]);
			mxnum[p] = func2(l[p], r[p]);
			for (int i = 0; i < BIT; i++) {
				sg[i].Insert(p, num[p][i], mxnum[p][i]);
			}
		}
		else {
			long long ans = 0;
			for (int i = 0; i < BIT; i++) {
				ans += sg[i].Accumulate();
			}
			cout << ans % MOD << endl;
		}
	}
}
accuracy: 1
time_ms: 10
memory_kb: 12108
final_rank: 2

code_snippet: #include "iostream"
#include "climits"
#include "list"
#include "queue"
#include "stack"
#include "set"
#include "functional"
#include "algorithm"
#include "string"
#include "map"
#include "unordered_map"
#include "unordered_set"
#include "iomanip"
#include "cmath"
#include "random"
#include "bitset"
#include "cstdio"
#include "numeric"
#include "cassert"
#include "ctime"

using namespace std;

constexpr long long MOD = 998244353;
constexpr int BIT = 20;

int N, K;

long long int power(long long int x, long long int n, long long int M) {
	long long int ret = 1;
	long long int by = x;
	while (n) {
		if (n & 1) {
			ret *= by;
			ret %= M;
		}
		by *= by;
		by %= M;
		n >>= 1;
	}
	return ret;
}

struct onoff {
	long long on, off;
	onoff(const long long off = 1, const long long on = 0) :off(off), on(on) {

	}
	onoff operator % (const long long mod)const {
		return onoff(off % MOD, on % MOD);
	}
	void operator %= (const long long mod) {
		off %= MOD;
		on %= MOD;
	}
	onoff operator + (const onoff& o)const {
		return onoff(off + o.off, on + o.on) % MOD;
	}
	void operator += (const onoff& o) {
		off += o.off;
		if (off >= MOD)off -= MOD;
		on += o.on;
		if (on >= MOD)on -= MOD;
	}
	onoff operator * (const onoff& o)const {
		return onoff(off * o.off + on * o.on, off * o.on + on * o.off) % MOD;
	}
	onoff operator *(const long long& v)const {
		return onoff(off * v, on * v) % MOD;
	}
	void operator *= (const onoff& o) {
		long long tmp = off;
		off = on * o.on + off * o.off;
		off %= MOD;
		on = tmp * o.on + on * o.off;
		on %= MOD;
	}
	void operator *= (const long long& by) {
		on *= by;
		on %= MOD;
		off *= by;
		off %= MOD;
	}
	onoff operator /(const long long& v)const {
		long long inv = power(v, MOD - 2, MOD);
		return onoff(off * inv, on * inv) % MOD;
	}
	void operator /= (const long long& by) {
		auto inv = power(by, MOD - 2, MOD);
		on *= inv;
		on %= MOD;
		off *= inv;
		off %= MOD;
	}
	void Output() {
		cout << "off = " << off << " on = " << on << endl;
	}
	onoff inv() {
		long long box = off * off + MOD - on * on % MOD;
		box %= MOD;
		box = power(box, MOD - 2, MOD);
		return onoff(off * box % MOD, MOD - on * box % MOD);
	}
};

class SegmentTree {
	int sz;
	vector<onoff>by;
	vector<onoff>sum;
	vector<int>l;
	vector<int>r;
	void Left(int place) {
		if (place >= sz / 2) {
			l[place] = place - sz / 2;
			return;
		}
		Left(place * 2);
		Left(place * 2 + 1);
		l[place] = l[place * 2];
		return;
	}
	void Right(int place) {
		if (place >= sz / 2) {
			r[place] = place - sz / 2;
			return;
		}
		Right(place * 2);
		Right(place * 2 + 1);
		r[place] = r[place * 2 + 1];
		return;
	}
	void Sum(int p) {
		if (p >= sz / 2) {
			
		}
		else {
			by[p] = by[p * 2] * by[p * 2 + 1];
			sum[p] = sum[p * 2] * by[p * 2 + 1];
			sum[p] += by[p * 2] * sum[p * 2 + 1];
		}
	}
	
public:
	SegmentTree(int n) {
		n++;
		sz = 1;
		while (sz * 2 < n * 4)sz <<= 1;
		sum.resize(sz);
		by.resize(sz);
		l.resize(sz);
		r.resize(sz);
		Left(1);
		Right(1);
		for (int i = sz / 2; i < sz; i++) {
			sum[i] = onoff(0, 0);
		}
		for (int i = sz / 2; i > 0; i--) {
			Sum(i);
		}
	}
	long long Accumulate() {
		return sum[1].off;
	}
	void Insert(int p, onoff num, onoff mxnum) {
		p += sz / 2;
		by[p] = num;
		sum[p] = mxnum;
		p >>= 1;
		while (p) {
			Sum(p);
			p >>= 1;
		}
	}
	void Debug() {
		cout << "sz = " << sz << endl;
	}
};


vector<onoff>func1(long long L, long long R) {
	vector<onoff>ret(BIT);
	long long by = 1;
	for (int j = 0; j < BIT; j++) {
		ret[j] = onoff(0, 0);
		by <<= 1;
		long long st = L / by;
		long long ed = R / by;
		ret[j].on += max(ed - st - 1, 0LL) * (by / 2);
		if (st < ed) {
			ret[j].on += max(0LL, R % by - by / 2 + 1);
			ret[j].on += min(by / 2, by - L % by);
		}
		else {
			ret[j].on += max(0LL, R % by - by / 2 + 1);
			if (L % by) {
				ret[j].on -= max(0LL, (L - 1) % by - by / 2 + 1);
			}
		}
		ret[j].on %= MOD;
	}
	for (int i = 0; i < BIT; i++) {
		ret[i].off = R - L + 1 - ret[i].on;
		ret[i].off %= MOD;
	}
	return ret;
}

vector<onoff>func2(long long L, long long R) {
	vector<onoff>ret(BIT);
	for (int j = 0; j < BIT; j++) {
		ret[j] = onoff(0, 0);
		ret[j].on = max(0LL, min((1LL << (j + 1)) - 1, R) - max(1LL << j, L) + 1);
		ret[j].on %= MOD;
	}
	return ret;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);

	cin >> N;
	vector<int>l(N);
	vector<int>r(N);
	vector<vector<onoff>>num(N, vector<onoff>(BIT));
	vector<vector<onoff>>mxnum(N, vector<onoff>(BIT));
	for (int i = 0; i < N; i++) {
		cin >> l[i] >> r[i];
		num[i] = func1(l[i], r[i]);
		mxnum[i] = func2(l[i], r[i]);
	}
	vector<SegmentTree>sg(BIT, SegmentTree(N));
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < BIT; j++) {
			sg[j].Insert(i, num[i][j], mxnum[i][j]);
		}
	}
	cin >> K;
	while (K--) {
		int a;
		cin >> a;
		if (a == 1) {
			int p, L, R;
			cin >> p >> L >> R;
			p--;
			l[p] = L;
			r[p] = R;
			num[p] = func1(l[p], r[p]);
			mxnum[p] = func2(l[p], r[p]);
			for (int i = 0; i < BIT; i++) {
				sg[i].Insert(p, num[p][i], mxnum[p][i]);
			}
		}
		else {
			long long ans = 0;
			for (int i = 0; i < BIT; i++) {
				ans += sg[i].Accumulate();
			}
			cout << ans % MOD << endl;
		}
	}
}
accuracy: 1
time_ms: 10
memory_kb: 12108
final_rank: 2

code_snippet: #include <algorithm>
#include <bitset>
#include <cmath>
#include <complex>
#include <cstdio>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <sys/types.h>
#include <unistd.h>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#pragma region macros
#define _overload(_1, _2, _3, name, ...) name
#define _rep(i, n) _range(i, 0, n)
#define _range(i, a, b) for (int i = int(a); i < int(b); ++i)
#define rep(...) _overload(__VA_ARGS__, _range, _rep, )(__VA_ARGS__)
#define _rrep(i, n) _rrange(i, n, 0)
#define _rrange(i, a, b) for (int i = int(a) - 1; i >= int(b); --i)
#define rrep(...) _overload(__VA_ARGS__, _rrange, _rrep, )(__VA_ARGS__)
#pragma endregion macros

using namespace std;

template <class T> bool chmax(T &a, const T &b) {
    return (a < b) ? (a = b, 1) : 0;
}
template <class T> bool chmin(T &a, const T &b) {
    return (b < a) ? (a = b, 1) : 0;
}

using ll    = long long;
using R     = long double;
const R EPS = 1e-9L;  // [-1000,1000]->EPS=1e-8 [-10000,10000]->EPS=1e-7
inline int sgn(const R &r) {
    return (r > EPS) - (r < -EPS);
}
inline R sq(R x) {
    return sqrt(max(x, 0.0L));
}

const int dx[8] = {1, 0, -1, 0, 1, -1, -1, 1};
const int dy[8] = {0, 1, 0, -1, 1, 1, -1, -1};

const pid_t pid = getpid();
// Problem Specific Parameter:

template <uint32_t MOD> class static_modint
{
  public:
    static_modint(): data(0) {}
    static_modint(int32_t y): data(y >= 0 ? y % MOD : MOD - (-y) % MOD) {}
    static_modint(int64_t y): data(y >= 0 ? y % MOD : MOD - (-y) % MOD) {}

    static static_modint raw(int32_t y) {
        static_modint ret;
        ret.data = y;
        return ret;
    }

    // Arithmetic Oprators
    static_modint &operator+=(const static_modint &that) {
        if ((data += that.data) >= MOD) {
            data -= MOD;
        }
        return *this;
    }
    static_modint &operator-=(const static_modint &that) {
        if ((data += MOD - that.data) >= MOD) {
            data -= MOD;
        }
        return *this;
    }
    static_modint &operator*=(const static_modint &that) {
        data = normalize(1LL * data * that.data);
        return *this;
    }
    static_modint &operator/=(const static_modint &that) {
        return *this *= static_modint(std::get<1>(extgcd(that.data, int(MOD))));
    }
    static_modint &operator%=(const static_modint &that) {
        data %= that.data;
        return *this;
    }

    static_modint &operator+=(const int that) {
        return *this += static_modint(that);
    }
    static_modint &operator-=(const int that) {
        return *this -= static_modint(that);
    }
    static_modint &operator*=(const int that) {
        return *this *= static_modint(that);
    }
    static_modint &operator/=(const int that) {
        return *this /= static_modint(that);
    }
    static_modint &operator%=(const int that) {
        return *this %= static_modint(that);
    }

    // Comparators
    bool operator<(const static_modint &that) {
        return data < that.data;
    }
    bool operator>(const static_modint &that) {
        return data > that.data;
    }
    bool operator<=(const static_modint &that) {
        return data <= that.data;
    }
    bool operator>=(const static_modint &that) {
        return data >= that.data;
    }
    bool operator!=(const static_modint &that) {
        return data != that.data;
    }
    bool operator==(const static_modint &that) {
        return data == that.data;
    }

    // Utilities
    unsigned val() const {
        return data;
    }

    static unsigned mod() {
        return MOD;
    }

    static_modint operator+(const static_modint &that) const {
        return static_modint(*this) += that;
    }
    static_modint operator-(const static_modint &that) const {
        return static_modint(*this) -= that;
    }
    static_modint operator*(const static_modint &that) const {
        return static_modint(*this) *= that;
    }
    static_modint operator/(const static_modint &that) const {
        return static_modint(*this) /= that;
    }
    static_modint operator%(const static_modint &that) const {
        return static_modint(*this) %= that;
    }
    static_modint operator+(const int that) const {
        return static_modint(*this) += that;
    }
    static_modint operator-(const int that) const {
        return static_modint(*this) -= that;
    }
    static_modint operator*(const int that) const {
        return static_modint(*this) *= that;
    }
    static_modint operator/(const int that) const {
        return static_modint(*this) /= that;
    }
    static_modint operator%(const int that) const {
        return static_modint(*this) %= that;
    }
    static_modint operator=(const int that) {
        return *this = static_modint(that);
    }
    friend std::istream &operator>>(std::istream &is, static_modint &that) {
        int64_t tmp;
        is >> tmp;
        that = static_modint(tmp);
        return is;
    }
    friend std::ostream &operator<<(std::ostream &os,
                                    const static_modint &that) {
        return os << that.data;
    }

    static_modint power(ll n) const {
        static_modint b = raw(1), a = *this;
        while (n) {
            if (n & 1) {
                b *= a;
            }
            a *= a;
            n >>= 1;
        }
        return b;
    }

  private:
    unsigned data;

    const static __int128 magic_number = (__int128(1) << 64) / MOD;

    uint64_t normalize(uint64_t x) const {
        const uint64_t q = (x * magic_number) >> 64;
        x -= q * MOD;
        return x < MOD ? x : x - MOD;
    }

    inline std::tuple<int32_t, int32_t, int32_t> extgcd(int32_t a,
                                                        int32_t b) const {
        if (b == 0) {
            return std::make_tuple(a, 1, 0);
        }
        int32_t g, x, y;
        tie(g, x, y) = extgcd(b, a % b);
        std::swap(x, y);
        y -= a / b * x;
        return make_tuple(g, x, y);
    }
};

using modint998244353 = static_modint<998244353>;

template <class S, S (*op)(S, S), S (*e)()> struct segtree {
  public:
    segtree(): segtree(0) {}
    explicit segtree(int n): segtree(std::vector<S>(n, e())) {}
    explicit segtree(const std::vector<S> &value): n(int(value.size())) {
        log  = 32 - __builtin_clz(n);
        size = 1 << log;
        data = std::vector<S>(2 * size, e());
        for (int i = 0; i < n; i++) {
            data[size + i] = value[i];
        }
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }

    void set(int p, S x) {
        p += size;
        data[p] = x;
        for (int i = 1; i <= log; i++) {
            update(p >> i);
        }
    }

    S get(int p) {
        return data[p + size];
    }

    S prod(int l, int r) {
        S sml = e(), smr = e();

        for (l += size, r += size; l < r; l >>= 1, r >>= 1) {
            if (l & 1) {
                sml = op(sml, data[l++]);
            }
            if (r & 1) {
                smr = op(data[--r], smr);
            }
        }

        return op(sml, smr);
    }

    S all_prod() {
        return data[1];
    }

  private:
    int n, size, log;
    std::vector<S> data;

    void update(int k) {
        data[k] = op(data[2 * k], data[2 * k + 1]);
    }
};


using mint = modint998244353;
using S    = struct {
    mint val[2];
    mint ans[2];
};

S op(S a, S b) {
    S ret;

    rep(i, 2) rep(j, 2) {
        ret.val[i ^ j] += a.val[i] * b.val[j];
        ret.ans[i ^ j] += a.ans[i] * b.val[j];
        ret.ans[i ^ j] += a.val[i] * b.ans[j];
    }

    return ret;
}

S e() {
    S ret;
    ret.val[0] = mint::raw(1);
    ret.val[1] = mint::raw(0);
    ret.ans[0] = mint::raw(0);
    ret.ans[1] = mint::raw(0);
    return ret;
}

const int amax = 1000010;

int get_cnt(int l, int r, int j) {
    const int lo = 1 << j;
    const int hi = lo << 1;

    const int lidx = l / hi;
    const int ridx = r / hi;

    int ret = 0;
    if (lidx == ridx) {
        ret += max(lo, r % hi) - max(lo, l % hi);
    } else {
        ret += hi - max(lo, l % hi);
        ret += max(lo, r % hi) - lo;
        ret += lo * (ridx - lidx - 1);
    }

    return ret;
}

int get_msb(int l, int r, int j) {
    const int lo = 1 << j;
    const int hi = lo << 1;
    return clamp(r, lo, hi) - clamp(l, lo, hi);
}

S get_element(int l, int r, int j) {
    const int all = r - l;
    const int cnt = get_cnt(l, r, j);
    const int msb = get_msb(l, r, j);

    S ret;
    ret.val[0] = mint::raw(all - cnt);
    ret.val[1] = mint::raw(cnt);
    ret.ans[1] = mint::raw(msb);

    // cerr << l << " " << r << " " << j << endl;
    // cerr << ret.val[0] << " " << ret.val[1] << endl;
    // cerr << ret.ans[0] << " " << ret.ans[1] << endl;

    return ret;
}

using segtree_t = segtree<S, op, e>;
segtree_t segtrees[20];


int main(void) {
    std::cin.tie(0);
    std::ios::sync_with_stdio(false);

    int n;
    cin >> n;

    rep(j, 20) {
        segtrees[j] = segtree_t(n);
    }

    rep(i, n) {
        int l, r;
        cin >> l >> r;
        r++;

        rep(j, 20) {
            segtrees[j].set(i, get_element(l, r, j));
        }
    }

    int q;
    cin >> q;

    rep(loop, q) {
        int k;
        cin >> k;
        if (k == 1) {
            int p, l, r;
            cin >> p >> l >> r;
            p--, r++;

            rep(j, 20) {
                segtrees[j].set(p, get_element(l, r, j));
            }
        } else {
            mint ans;
            rep(j, 20) {
                const mint val = segtrees[j].all_prod().ans[0];
                // cerr << val << endl;
                ans += val;
            }
            cout << ans.val() << endl;
        }
    }

    return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 5876
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using vl = vector<ll>;
template<class T> using vc = vector<T>;
template<class T> using vvc = vector<vector<T>>;

#define eb emplace_back
#define all(x) (x).begin(), (x).end()
#define rep(i, n) for (ll i = 0; i < (n); i++)
#define repr(i, n) for (ll i = (n)-1; i >= 0; i--)
#define repe(i, l, r) for (ll i = (l); i < (r); i++)
#define reper(i, l, r) for (ll i = (r)-1; i >= (l); i--)
#define repa(i,n) for (auto& i: n)

template<class T1, class T2> inline bool chmax(T1 &a, const T2 &b) {if (a<b) { a=b; return 1;} return 0;}
template<class T1, class T2> inline bool chmin(T1 &a, const T2 &b) {if (b<a) { a=b; return 1;} return 0;}
struct init{init(){cin.tie(0);ios::sync_with_stdio(false);cout<<fixed<<setprecision(15);cerr<<fixed<<setprecision(15);}}init_;

#ifdef DEBUG
template <class T> void verr(const set<T> &st) { repa(a, st) cerr << a << " "; cerr << endl; }
template <class S, class T> void verr(const map<S, T> &mp) { repa(a, mp) cerr << "{" << a.first << ", " << a.second << "} "; cerr << endl; }
template <class S, class T, class N> void verr(const vector<pair<S,T>>& a, const N& n) { rep(i, n) cerr << "{" << a[i].first << ", " << a[i].second << "} "; cerr << endl; }
template <class T, class N> void verr(const vector<T>& a, const N& n) { rep(i, n) cerr << a[i] << " "; cerr << endl; }
ll dbgt = 1; void err() { cerr << "passed " << dbgt++ << endl; }
template<class H, class... T> void err(H&& h,T&&... t){ cerr<< h << (sizeof...(t)?" ":"\n") << flush; if(sizeof...(t)>0) err(forward<T>(t)...); }
#endif

const ll INF = 4e18;
const ld EPS = 1e-11;
const ld PI = acos(-1.0L);
// const ll MOD = 1e9 + 7;
const ll MOD = 998244353;
const ll BIT = 20;
//--------------------------------------------------------------------------------//
ll modpow(ll a, ll n, ll mod) {
    ll res = 1;
    while (n > 0) {
        if (n & 1) res = res * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return res;
}


vvc<ll> count_jbit(ll L, ll R){
    vvc<ll> ret(BIT, vl(2));
    rep(j, BIT){
        ll by = 1 << (j + 1);
        ll st = L / by, ed = R / by;
        ret[j][1] += max(ed - st - 1, 0ll) * (by / 2);
        if(st < ed) {
            ret[j][1] += max(0ll, R % by - by / 2 + 1);
            ret[j][1] += min(by / 2, by - L % by);
        }else{
            ret[j][1] += max(0ll, R % by - by / 2 + 1);
            if(L % by) {
                ret[j][1] -= max(0ll, (L - 1) % by - by / 2 + 1);
            }
        }
        ret[j][0] = (R - L + 1) - ret[j][1];
    }
    return ret;
}

vvc<ll> count_highest_bit(ll L, ll R){
    vvc<ll> ret(BIT, vl(2));
    rep(j, BIT){
        ret[j][1] = (max(0ll, min((1ll << (j + 1)) - 1, R) - max(1ll << j, L) + 1)) % MOD;
    }
    return ret;
}

vl get_num_inv(vl num){
    assert(0 <= num[0] and num[0] < MOD and 0 <= num[1] and num[1] < MOD);
    if(num[0] == num[1]){
        return {-1, -1};
    }
    ll bunbo = modpow(((num[0] * num[0] - num[1] * num[1]) % MOD + MOD) % MOD, MOD - 2, MOD);

    vl ret(2);
    ret[0] = num[0] * bunbo % MOD, ret[1] = (MOD - num[1]) * bunbo % MOD;
    return ret;
}

vl xor_convolute(vl num1, vl num2){
    vl ret(2);
    ret[0] = (num1[0] * num2[0] + num1[1] * num2[1]) % MOD;
    ret[1] = (num1[0] * num2[1] + num1[1] * num2[0]) % MOD;
    return ret;
}

int main() {
    ll N;
    cin >> N;
    vl L(N), R(N);
    rep(i, N) cin >> L[i] >> R[i];
    vl p2(N + 1, 1);
    rep(i, N) p2[i + 1] = p2[i] * 2 % MOD;

    vc<vvc<ll>> num(N, vvc<ll>(BIT, vl(2))), mxnum(N, vvc<ll>(BIT, vl(2))), num_inv(N, vvc<ll>(BIT, vl(2)));
    vc<set<ll>> same_counts(BIT);
    vl same_coef(BIT, 1);

    rep(i, N) {
        num[i] = count_jbit(L[i], R[i]);
        mxnum[i] = count_highest_bit(L[i], R[i]);
        rep(j, BIT) {
            if(num[i][j][0] == num[i][j][1]){
                same_counts[j].emplace(i);
                (same_coef[j] *= num[i][j][0]) %= MOD;
                ll c = modpow(num[i][j][0] * 4, MOD - 2, MOD);
                num_inv[i][j] = {c, c};
            }else{
                num_inv[i][j] = get_num_inv(num[i][j]);
            }
        }
    }

    vvc<ll> num_prod(BIT, vl(2)), num_sum(BIT, vl(2));
    rep(j, BIT) {
        rep(i, N){
            (num_sum[j][0] += mxnum[i][j][1] * num_inv[i][j][0]) %= MOD;
            (num_sum[j][1] += mxnum[i][j][1] * num_inv[i][j][1]) %= MOD;
        }
        num_prod[j][0] = 1;
        rep(i, N) {
            if(num[i][j][0] != num[i][j][1])
                num_prod[j] = xor_convolute(num_prod[j], num[i][j]);
        }
    }


    ll Q;
    cin >> Q;
    rep(qi, Q){
        ll k;
        cin >> k;
        if(k == 1){
            ll p, l, r;
            cin >> p >> l >> r, p--;
            
            rep(j, BIT) {
                (num_sum[j][0] += MOD - mxnum[p][j][1] * num_inv[p][j][0] % MOD) %= MOD;
                (num_sum[j][1] += MOD - mxnum[p][j][1] * num_inv[p][j][1] % MOD) %= MOD;
                
                if(num[p][j][0] == num[p][j][1]){
                    same_counts[j].erase(p);
                    (same_coef[j] *= modpow(num[p][j][0], MOD - 2, MOD)) %= MOD;
                }else{
                    num_prod[j] = xor_convolute(num_prod[j], num_inv[p][j]);
                }
            }

            num[p] = count_jbit(l, r);
            mxnum[p] = count_highest_bit(l, r);

            rep(j, BIT) {
                if(num[p][j][0] == num[p][j][1]){
                    same_counts[j].emplace(p);
                    (same_coef[j] *= num[p][j][0]) %= MOD;
                    ll c = modpow(num[p][j][0] * 4, MOD - 2, MOD);
                    num_inv[p][j] = {c, c};
                }else{
                    num_inv[p][j] = get_num_inv(num[p][j]);
                    num_prod[j] = xor_convolute(num_prod[j], num[p][j]);
                }
                (num_sum[j][0] += mxnum[p][j][1] * num_inv[p][j][0]) %= MOD;
                (num_sum[j][1] += mxnum[p][j][1] * num_inv[p][j][1]) %= MOD;
            }
            
        }else {
            ll ans = 0;
            rep(j, BIT) {
                vl cur_sum = num_sum[j], cur_prod = num_prod[j];
                if (same_counts[j].size() == 1) {
                    ll idx = *same_counts[j].begin();
                    (cur_sum[0] -= (mxnum[idx][j][1] * num_inv[idx][j][0])) %= MOD;
                    (cur_sum[1] -= (mxnum[idx][j][1] * num_inv[idx][j][1])) %= MOD;
                    (ans += mxnum[idx][j][1] * num_prod[j][1]) %= MOD;
                }

                if (same_counts[j].size() > 0) {
                    cur_prod[0] += cur_prod[1];
                    cur_prod[1] = cur_prod[0];
                }

                auto ans_sum = xor_convolute(cur_prod, cur_sum);
                (ans_sum[1] *= p2[max(0ll, (ll)same_counts[j].size() - 1)] * same_coef[j] % MOD) %= MOD;
                (ans += ans_sum[1]) %= MOD;
            }
            cout << (ans % MOD + MOD) % MOD << '\n';
        }
    }
}
accuracy: 1
time_ms: 30
memory_kb: 13856
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using PII = pair<ll, ll>;
#define FOR(i, a, n) for (ll i = (ll)a; i < (ll)n; ++i)
#define REP(i, n) FOR(i, 0, n)
#define ALL(x) x.begin(), x.end()
template<typename T> void chmin(T &a, const T &b) { a = min(a, b); }
template<typename T> void chmax(T &a, const T &b) { a = max(a, b); }
struct FastIO {FastIO() { cin.tie(0); ios::sync_with_stdio(0); }}fastiofastio;
const ll INF = 1LL<<60;

template<ll MOD>
struct modint {
    ll x;
    modint(): x(0) {}
    modint(ll y) : x(y>=0 ? y%MOD : y%MOD+MOD) {}
    static constexpr ll mod() { return MOD; }
    // e乗
    modint pow(ll e) {
        ll a = 1, p = x;
        while(e > 0) {
            if(e%2 == 0) {p = (p*p) % MOD; e /= 2;}
            else {a = (a*p) % MOD; e--;}
        }
        return modint(a);
    }
    modint inv() const {
        ll a=x, b=MOD, u=1, y=1, v=0, z=0;
        while(a) {
            ll q = b/a;
            swap(z -= q*u, u);
            swap(y -= q*v, v);
            swap(b -= q*a, a);
        }
        return z;
    }
    // Comparators
    bool operator <(modint b) { return x < b.x; }
    bool operator >(modint b) { return x > b.x; }
    bool operator<=(modint b) { return x <= b.x; }
    bool operator>=(modint b) { return x >= b.x; }
    bool operator!=(modint b) { return x != b.x; }
    bool operator==(modint b) { return x == b.x; }
    // Basic Operations
    modint operator+(modint r) const { return modint(*this) += r; }
    modint operator-(modint r) const { return modint(*this) -= r; }
    modint operator*(modint r) const { return modint(*this) *= r; }
    modint operator/(modint r) const { return modint(*this) /= r; }
    modint &operator+=(modint r) {
        if((x += r.x) >= MOD) x -= MOD;
        return *this;
    }
    modint &operator-=(modint r) {
        if((x -= r.x) < 0) x += MOD;
        return *this;
    }
    modint &operator*=(modint r) {
    #if !defined(_WIN32) || defined(_WIN64)
        x = (ll)x * r.x % MOD; return *this;
    #endif
        unsigned long long y = (unsigned long long)x * r.x;
        unsigned xh = (unsigned) (y >> 32), xl = (unsigned) y, d, m;
        asm(
            "divl %4; \n\t"
            : "=a" (d), "=d" (m)
            : "d" (xh), "a" (xl), "r" (MOD)
        );
        x = m;
        return *this;
    }
    modint &operator/=(modint r) { return *this *= r.inv(); }
    // increment, decrement
    modint operator++() { x++; return *this; }
    modint operator++(signed) { modint t = *this; x++; return t; }
    modint operator--() { x--; return *this; }
    modint operator--(signed) { modint t = *this; x--; return t; }
    // 平方剰余のうち一つを返す なければ-1
    friend modint sqrt(modint a) {
        if(a == 0) return 0;
        ll q = MOD-1, s = 0;
        while((q&1)==0) q>>=1, s++;
        modint z=2;
        while(1) {
            if(z.pow((MOD-1)/2) == MOD-1) break;
            z++;
        }
        modint c = z.pow(q), r = a.pow((q+1)/2), t = a.pow(q);
        ll m = s;
        while(t.x>1) {
            modint tp=t;
            ll k=-1;
            FOR(i, 1, m) {
                tp *= tp;
                if(tp == 1) { k=i; break; }
            }
            if(k==-1) return -1;
            modint cp=c;
            REP(i, m-k-1) cp *= cp;
            c = cp*cp, t = c*t, r = cp*r, m = k;
        }
        return r.x;
    }

    template<class T>
    friend modint operator*(T l, modint r) { return modint(l) *= r; }
    template<class T>
    friend modint operator+(T l, modint r) { return modint(l) += r; }
    template<class T>
    friend modint operator-(T l, modint r) { return modint(l) -= r; }
    template<class T>
    friend modint operator/(T l, modint r) { return modint(l) /= r; }
    template<class T>
    friend bool operator==(T l, modint r) { return modint(l) == r; }
    template<class T>
    friend bool operator!=(T l, modint r) { return modint(l) != r; }
    // Input/Output
    friend ostream &operator<<(ostream& os, modint a) { return os << a.x; }
    friend istream &operator>>(istream& is, modint &a) { 
        is >> a.x;
        a.x = ((a.x%MOD)+MOD)%MOD;
        return is;
    }
    friend string to_frac(modint v) {
        static map<ll, PII> mp;
        if(mp.empty()) {
            mp[0] = mp[MOD] = {0, 1};
            FOR(i, 2, 1001) FOR(j, 1, i) if(__gcd(i, j) == 1) {
                mp[(modint(i) / j).x] = {i, j};
            }
        }
        auto itr = mp.lower_bound(v.x);
        if(itr != mp.begin() && v.x - prev(itr)->first < itr->first - v.x) --itr;
        string ret = to_string(itr->second.first + itr->second.second * ((int)v.x - itr->first));
        if(itr->second.second > 1) {
            ret += '/';
            ret += to_string(itr->second.second);
        }
        return ret;
    }
};
using mint = modint<998244353>;

mint zero[3005][20], one[3005][20], msb[3005][20], rec[25][2][2];
void cnt(ll l, ll r, ll idx) {
	// **0**, **1**, 001** の数を数える
	REP(i, 20) {
		REP(x, 25) REP(y, 2) REP(z, 2) rec[x][y][z] = 0;
		rec[0][0][0] = 1;
		REP(x, 20) REP(y, 2) REP(z, 2) {
			ll now = 0, lb = !!(l & 1LL<<(19-x)), ub = !!(r & 1LL<<(19-x));
			if((y || lb <= now) && (z || now <= ub)) {
				rec[x+1][y || lb < now][z || now < ub] += rec[x][y][z];
			}
			now = 1;
			if(x != i && (y || lb <= now) && (z || now <= ub)) {
				rec[x+1][y || lb < now][z || now < ub] += rec[x][y][z];
			}
		}
		zero[idx][i] = 0;
		REP(y, 2) REP(z, 2) zero[idx][i] += rec[20][y][z];

		REP(x, 25) REP(y, 2) REP(z, 2) rec[x][y][z] = 0;
		rec[0][0][0] = 1;
		REP(x, 20) REP(y, 2) REP(z, 2) {
			ll now = 0, lb = !!(l & 1LL<<(19-x)), ub = !!(r & 1LL<<(19-x)); 
			if(x != i && (y || lb <= now) && (z || now <= ub)) {
				rec[x+1][y || lb < now][z || now < ub] += rec[x][y][z];
			}
			now = 1;
			if((y || lb <= now) && (z || now <= ub)) {
				rec[x+1][y || lb < now][z || now < ub] += rec[x][y][z];
			}
		}
		one[idx][i] = 0;
		REP(y, 2) REP(z, 2) one[idx][i] += rec[20][y][z];

		REP(x, 25) REP(y, 2) REP(z, 2) rec[x][y][z] = 0;
		rec[0][0][0] = 1;
		REP(x, 20) REP(y, 2) REP(z, 2) {
			ll now = 0, lb = !!(l & 1LL<<(19-x)), ub = !!(r & 1LL<<(19-x)); 
			if(x != i && (y || lb <= now) && (z || now <= ub)) {
				rec[x+1][y || lb < now][z || now < ub] += rec[x][y][z];
			}
			now = 1;
			if(x >= i && (y || lb <= now) && (z || now <= ub)) {
				rec[x+1][y || lb < now][z || now < ub] += rec[x][y][z];
			}
		}
		msb[idx][i] = 0;
		REP(y, 2) REP(z, 2) msb[idx][i] += rec[20][y][z];
	}
}

mint dp[3005][2], rev[3005][2];
mint solve(ll n) {
	mint ans = 0;
	REP(i, 20) {
		dp[0][0] = zero[0][i], dp[0][1] = one[0][i];
		FOR(j, 1, n) {
			dp[j][0] = dp[j-1][0] * zero[j][i] + dp[j-1][1] * one[j][i];
			dp[j][1] = dp[j-1][0] * one[j][i] + dp[j-1][1] * zero[j][i];
		}
		rev[n-1][0] = zero[n-1][i], rev[n-1][1] = one[n-1][i];
		for(ll j=n-2; j>=0; --j) {
			rev[j][0] = rev[j+1][0] * zero[j][i] + rev[j+1][1] * one[j][i];
			rev[j][1] = rev[j+1][0] * one[j][i] + rev[j+1][1] * zero[j][i];
		}

		REP(j, n) {
			mint tmp = 0;
			if(j != n-1) tmp += (j == 0 ? 1 : dp[j-1][0]) * rev[j+1][1];
			if(j != 0) tmp += dp[j-1][1] * (j == n-1 ? 1 : rev[j+1][0]);
			ans += msb[j][i] * tmp;
		}
	}
	return ans;
}

int main() {
	ll n;
	cin >> n;
	vector<ll> l(n), r(n);
	REP(i, n) cin >> l[i] >> r[i], cnt(l[i], r[i], i);

	ll q;
	cin >> q;
	REP(i, q) {
		ll k;
		cin >> k;
		if(k == 1) {
			ll x, y, z;
			cin >> x >> y >> z;
			cnt(y, z, x-1);
		} else {
			cout << solve(n) << "\n";
		}
	}
}
accuracy: 1
time_ms: 1520
memory_kb: 4996
final_rank: 12

code_snippet: #include "iostream"
#include "climits"
#include "list"
#include "queue"
#include "stack"
#include "set"
#include "functional"
#include "algorithm"
#include "string"
#include "map"
#include "unordered_map"
#include "unordered_set"
#include "iomanip"
#include "cmath"
#include "random"
#include "bitset"
#include "cstdio"
#include "numeric"
#include "cassert"
#include "ctime"

using namespace std;

constexpr long long MOD = 998244353;
constexpr int BIT = 20;

int N, K;

long long int power(long long int x, long long int n, long long int M) {
	long long int ret = 1;
	long long int by = x;
	while (n) {
		if (n & 1) {
			ret *= by;
			ret %= M;
		}
		by *= by;
		by %= M;
		n >>= 1;
	}
	return ret;
}

struct onoff {
	long long on, off;
	onoff(const long long off = 1, const long long on = 0) :off(off), on(on) {

	}
	onoff operator % (const long long mod)const {
		return onoff(off % MOD, on % MOD);
	}
	void operator %= (const long long mod) {
		off %= MOD;
		on %= MOD;
	}
	onoff operator + (const onoff& o)const {
		return onoff(off + o.off, on + o.on) % MOD;
	}
	void operator += (const onoff& o) {
		off += o.off;
		if (off >= MOD)off -= MOD;
		on += o.on;
		if (on >= MOD)on -= MOD;
	}
	onoff operator * (const onoff& o)const {
		return onoff(off * o.off + on * o.on, off * o.on + on * o.off) % MOD;
	}
	onoff operator *(const long long& v)const {
		return onoff(off * v, on * v) % MOD;
	}
	void operator *= (const onoff& o) {
		long long tmp = off;
		off = on * o.on + off * o.off;
		off %= MOD;
		on = tmp * o.on + on * o.off;
		on %= MOD;
	}
	void operator *= (const long long& by) {
		on *= by;
		on %= MOD;
		off *= by;
		off %= MOD;
	}
	onoff operator /(const long long& v)const {
		long long inv = power(v, MOD - 2, MOD);
		return onoff(off * inv, on * inv) % MOD;
	}
	void operator /= (const long long& by) {
		auto inv = power(by, MOD - 2, MOD);
		on *= inv;
		on %= MOD;
		off *= inv;
		off %= MOD;
	}
	void Output() {
		cout << "off = " << off << " on = " << on << endl;
	}
	onoff inv() {
		long long box = off * off + MOD - on * on % MOD;
		box %= MOD;
		box = power(box, MOD - 2, MOD);
		return onoff(off * box % MOD, MOD - on * box % MOD);
	}
};

class SegmentTree {
	int sz;
	vector<onoff>eq;
	vector<onoff>neq;
	vector<onoff>sum;
	vector<int>eqnum;
	vector<int>zero;
	vector<int>l;
	vector<int>r;
	void Left(int place) {
		if (place >= sz / 2) {
			l[place] = place - sz / 2;
			return;
		}
		Left(place * 2);
		Left(place * 2 + 1);
		l[place] = l[place * 2];
		return;
	}
	void Right(int place) {
		if (place >= sz / 2) {
			r[place] = place - sz / 2;
			return;
		}
		Right(place * 2);
		Right(place * 2 + 1);
		r[place] = r[place * 2 + 1];
		return;
	}
	void Sum(int p) {
		if (p >= sz / 2) {
			sum[p] = neq[p] * eq[p];
			if (zero[p])sum[p] = onoff(0, 0);
		}
		else {
			sum[p] = sum[p * 2] + sum[p * 2 + 1];
			sum[p] *= eq[p] * neq[p];
		}
	}
	void MulNeq(int L, int R, int p, onoff o) {
		if (L <= l[p] && r[p] <= R) {
			neq[p] *= o;
			Sum(p);
			return;
		}
		if (r[p] < L || R < l[p]) {
			return;
		}
		MulNeq(L, R, p * 2, o);
		MulNeq(L, R, p * 2 + 1, o);
		Sum(p);
	}
	void MulEq(int L, int R, int p, onoff o) {
		if (L <= l[p] && r[p] <= R) {
			eqnum[p]++;
			eq[p] *= o;
			Sum(p);
			return;
		}
		if (r[p] < L || R < l[p]) {
			return;
		}
		MulEq(L, R, p * 2, o);
		MulEq(L, R, p * 2 + 1, o);
		Sum(p);
	}
	void MulEqInv(int L, int R, int p, onoff o) {
		if (L <= l[p] && r[p] <= R) {
			eqnum[p]--;
			eq[p] /= o.off * 2;
			if (eqnum[p] == 0) {
				eq[p] = onoff();
			}
			Sum(p);
			return;
		}
		if (r[p] < L || R < l[p]) {
			return;
		}
		MulEqInv(L, R, p * 2, o);
		MulEqInv(L, R, p * 2 + 1, o);
		Sum(p);
	}
	void FlipZero(int L, int R, int p) {
		if (L <= l[p] && r[p] <= R) {
			zero[p] ^= 1;
			Sum(p);
			return;
		}
		if (r[p] < L || R < l[p]) {
			return;
		}
		FlipZero(L, R, p * 2);
		FlipZero(L, R, p * 2 + 1);
		Sum(p);
	}
public:
	SegmentTree(int n) {
		n++;
		sz = 1;
		while (sz * 2 < n*4)sz <<= 1;
		eq.resize(sz);
		neq.resize(sz);
		l.resize(sz);
		r.resize(sz);
		Left(1);
		Right(1);
		sum.resize(sz);
		eqnum.resize(sz);
		zero.resize(sz);
		for (int i = 0; i < N; i++) {
			Sum(i + sz / 2);
		}
		for (int i = N; i < sz / 2; i++) {
			zero[i+sz/2] = 1;
			Sum(i + sz / 2);
		}
		for (int i = sz / 2; i > 0; i--) {
			Sum(i);
		}
	}
	long long Accumulate() {
		return sum[1].off;
	}
	void MulSingle(int p, onoff o) {
		if (o.on == o.off) {
			FlipZero(p, p, 1);
		}
		else {
			MulNeq(p, p, 1, o);
		}
	}
	void MulSingleInv(int p, onoff o) {
		if (o.on == o.off) {
			FlipZero(p, p, 1);
		}
		else {
			MulNeq(p, p, 1, o.inv());
		}
	}
	void MulRange(int p, onoff o) {
		if (o.on == o.off) {
			if (p)MulEq(0, p - 1, 1, o);
			if (p + 1 < N)MulEq(p + 1, N - 1, 1, o);
		}
		else {
			if (p)MulNeq(0, p - 1, 1, o);
			if (p + 1 < N)MulNeq(p + 1, N - 1, 1, o);
		}
	}
	void MulRangeInv(int p, onoff o) {
		if (o.on == o.off) {
			if (p)MulEqInv(0, p - 1, 1, o);
			if (p + 1 < N)MulEqInv(p + 1, N - 1, 1, o);
		}
		else {
			if (p)MulNeq(0, p - 1, 1, o.inv());
			if (p + 1 < N)MulNeq(p + 1, N - 1, 1, o.inv());
		}
	}
	void Debug() {
		cout << "sz = " << sz << endl;
	}
};


vector<onoff>func1(long long L, long long R) {
	vector<onoff>ret(BIT);
	long long by = 1;
	for (int j = 0; j < BIT; j++) {
		ret[j] = onoff(0, 0);
		by <<= 1;
		long long st = L / by;
		long long ed = R / by;
		ret[j].on += max(ed - st - 1, 0LL) * (by / 2);
		if (st < ed) {
			ret[j].on += max(0LL, R % by - by / 2 + 1);
			ret[j].on += min(by / 2, by - L % by);
		}
		else {
			ret[j].on += max(0LL, R % by - by / 2 + 1);
			if (L % by) {
				ret[j].on -= max(0LL, (L - 1) % by - by / 2 + 1);
			}
		}
		ret[j].on %= MOD;
	}
	for (int i = 0; i < BIT; i++) {
		ret[i].off = R - L + 1 - ret[i].on;
		ret[i].off %= MOD;
	}
	return ret;
}

vector<onoff>func2(long long L, long long R) {
	vector<onoff>ret(BIT);
	for (int j = 0; j < BIT; j++) {
		ret[j] = onoff(0, 0);
		ret[j].on = max(0LL, min((1LL << (j + 1)) - 1, R) - max(1LL << j, L) + 1);
		ret[j].on %= MOD;
	}
	return ret;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);

	cin >> N;
	vector<int>l(N);
	vector<int>r(N);
	vector<vector<onoff>>num(N, vector<onoff>(BIT));
	vector<vector<onoff>>mxnum(N, vector<onoff>(BIT));
	for (int i = 0; i < N; i++) {
		cin >> l[i] >> r[i];
		num[i] = func1(l[i], r[i]);
		mxnum[i] = func2(l[i], r[i]);
	}
	vector<SegmentTree>sg(BIT, SegmentTree(N));
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < BIT; j++) {
			sg[j].MulSingle(i, mxnum[i][j]);
			sg[j].MulRange(i, num[i][j]);
		}
	}
	cin >> K;
	while (K--) {
		int a;
		cin >> a;
		if (a == 1) {
			int p, L, R;
			cin >> p >> L >> R;
			p--;
			for (int i = 0; i < BIT; i++) {
				sg[i].MulSingleInv(p, mxnum[p][i]);
				sg[i].MulRangeInv(p, num[p][i]);
			}
			l[p] = L;
			r[p] = R;
			num[p] = func1(l[p], r[p]);
			mxnum[p] = func2(l[p], r[p]);
			for (int i = 0; i < BIT; i++) {
				sg[i].MulSingle(p, mxnum[p][i]);
				sg[i].MulRange(p, num[p][i]);
			}
		}
		else {
			long long ans = 0;
			for (int i = 0; i < BIT; i++) {
				ans += sg[i].Accumulate();
			}
			cout << ans % MOD << endl;
		}
	}
}
accuracy: 1
time_ms: 110
memory_kb: 16300
final_rank: 6

code_snippet: #include "bits/stdc++.h"

using namespace std;

constexpr long long MOD = 998244353;
constexpr int BIT = 20;

long long int gcd(long long a, long long b) {
	while (b) {
		a %= b;
		swap(a, b);
	}
	return a;
}

long long int power(long long int x, long long int n, long long int M) {
	long long int ret = 1;
	long long int by = x;
	while (n) {
		if (n & 1) {
			ret *= by;
			ret %= M;
		}
		by *= by;
		by %= M;
		n >>= 1;
	}
	return ret;
}

long long int extended_gcd(long long int a, long long int b, long long int c, long long int d, long long int m) {
	long long int ret = 0;
	if (c == 1)return d;
	ret = extended_gcd(c, d, a % c, (b + (MOD * MOD / m) * m - ((a / c) % m) * (d % m)) % m, m);
	return ret;
}

long long int extended_gcd(long long int a, long long int b) {
	long long int g = gcd(a, b);
	a /= g;
	b /= g;
	long long int box = a % b;
	long long int bag = b - (a % b);
	long long int bbox = 1;
	long long int bbag = b - 1;
	return extended_gcd(box, bbox, bag, bbag, b) * g;
}

struct onoff {
	long long on, off;
	onoff(const long long off = 1, const long long on = 1) :off(off), on(on) {

	}
	onoff operator % (const long long mod)const {
		return onoff(off % MOD, on % MOD);
	}
	void operator %= (const long long mod) {
		off %= MOD;
		on %= MOD;
	}
	onoff operator + (const onoff& o)const {
		return onoff(off + o.off, on + o.on) % MOD;
	}
	void operator += (const onoff& o) {
		off += o.off;
		if (off >= MOD)off -= MOD;
		on += o.on;
		if (on >= MOD)on -= MOD;
	}
	onoff operator * (const onoff& o)const {
		return onoff(off * o.off + on * o.on, off * o.on + on * o.off) % MOD;
	}
	onoff operator *(const long long& v)const {
		return onoff(off * v, on * v) % MOD;
	}
	void operator *= (const onoff& o) {
		long long tmp = off;
		off = on * o.on + off * o.off;
		off %= MOD;
		on = tmp * o.on + on * o.off;
		on %= MOD;
	}
	void operator *= (const long long& by) {
		on *= by;
		on %= MOD;
		off *= by;
		off %= MOD;
	}
	onoff operator /(const long long& v)const {
		long long inv = power(v, MOD - 2, MOD);
		return onoff(off * inv, on * inv) % MOD;

	}
	void Output() {
		cout << "off = " << off << " on = " << on << endl;
	}
	onoff inv() {
		long long box = off * off + MOD - on * on % MOD;
		box %= MOD;
		long long c = extended_gcd(box, MOD);
		return onoff(off * c % MOD, MOD - on * c % MOD);
	}
};

class Add_Segment_Tree {
	vector<onoff>v;
	vector<onoff>w;
	vector<int>wflag;
	vector<onoff>mul;
	vector<int>l;
	vector<int>r;
	vector<int>zero;
	int num;
	onoff ret;
	void Left(int place) {
		if (place >= v.size() / 2) {
			l[place] = place - v.size() / 2;
			return;
		}
		Left(place * 2);
		Left(place * 2 + 1);
		l[place] = l[place * 2];
		return;
	}
	void Right(int place) {
		if (place >= v.size() / 2) {
			r[place] = place - v.size() / 2;
			return;
		}
		Right(place * 2);
		Right(place * 2 + 1);
		r[place] = r[place * 2 + 1];
		return;
	}
	void Spread(int place) {
		mul[place * 2] *= mul[place];
		mul[place * 2 + 1] *= mul[place];
		mul[place] = onoff(1, 0);
	}
	void Collect(int place) {
		v[place] = onoff(0, 0);
		v[place] += v[place * 2] * mul[place * 2] * zero[place * 2] * w[place * 2];
		v[place] += v[place * 2 + 1] * mul[place * 2 + 1] * zero[place * 2 + 1] * w[place * 2 + 1];
		return;
	}
	void Mul(int a, int b, onoff o, int place) {
		if (l[place] >= a && r[place] <= b) {
			mul[place] *= o;
			return;
		}
		if (l[place] > b || r[place] < a)return;
		Spread(place);
		Mul(a, b, o, place * 2);
		Mul(a, b, o, place * 2 + 1);
		Collect(place);
		return;
	}
	void MulSame(int a, int b, long long by, int place) {
		if (l[place] >= a && r[place] <= b) {
			if (wflag[place]) {
				w[place] *= by * 2;
			}
			else {
				w[place] = onoff(by, by);
			}
			wflag[place]++;
			return;
		}
		if (l[place] > b || r[place] < a)return;
		Spread(place);
		MulSame(a, b, by, place * 2);
		MulSame(a, b, by, place * 2 + 1);
		Collect(place);
		return;
	}
	void DivSame(int a, int b, long long by, int place) {
		if (l[place] >= a && r[place] <= b) {
			wflag[place]--;
			if (wflag[place]) {
				w[place] *= by;
			}
			else {
				w[place] = onoff(1, 0);
			}
			return;
		}
		if (l[place] > b || r[place] < a)return;
		Spread(place);
		DivSame(a, b, by, place * 2);
		DivSame(a, b, by, place * 2 + 1);
		Collect(place);
		return;
	}
	void Sum(int a, int b, int place) {
		if (l[place] >= a && r[place] <= b) {
			ret += v[place] * w[place] * mul[place] * zero[place];
			return;
		}
		if (l[place] > b || r[place] < a)return;
		Spread(place);
		Sum(a, b, place * 2);
		Sum(a, b, place * 2 + 1);
		Collect(place);
		return;
	}
	void Zero(int a, int b, int place) {
		if (l[place] >= a && r[place] <= b) {
			zero[place] ^= 1;
			return;
		}
		if (l[place] > b || r[place] < a)return;
		Spread(place);
		Zero(a, b, place * 2);
		Zero(a, b, place * 2 + 1);
		Collect(place);
		return;
	}
public:
	Add_Segment_Tree(int n) {
		n++;
		num = 1;
		while (num < n * 2) {
			num *= 2;
		}
		l.resize(num);
		r.resize(num);
		zero.resize(num, 1);
		wflag.resize(num, 0);
		v.resize(num, onoff(1, 0));
		w.resize(num, onoff(1, 0));
		mul.resize(num, onoff(1, 0));
		Left(1);
		Right(1);
		for (int i = 0; i < num; i++) {
			v[i].off = r[i] - l[i] + 1;
		}
	}
	void Zero(int a, int b) {
		Zero(a, b, 1);
	}
	void Mul(int a, int b, onoff o) {
		Mul(a, b, o, 1);
	}
	void MulSame(int a, int b, long long by) {
		MulSame(a, b, by, 1);
	}
	void DivSame(int a, int b, long long by) {
		DivSame(a, b, power(by * 2, MOD - 2, MOD), 1);
	}
	onoff Sum(int a, int b) {
		ret = { 0,0 };
		Sum(a, b, 1);
		return ret;
	}
};

vector<long long>func1(long long L, long long R) {
	vector<long long>ret(BIT);
	long long by = 1;
	for (int j = 0; j < BIT; j++) {
		by <<= 1;
		long long st = L / by;
		long long ed = R / by;
		ret[j] += max(ed - st - 1, 0LL) * (by / 2);
		if (st < ed) {
			ret[j] += max(0LL, R % by - by / 2 + 1);
			ret[j] += min(by / 2, by - L % by);
		}
		else {
			ret[j] += max(0LL, R % by - by / 2 + 1);
			if (L % by) {
				ret[j] -= max(0LL, (L - 1) % by - by / 2 + 1);
			}
		}
		ret[j] %= MOD;
	}
	return ret;
}

vector<long long>func2(long long L, long long R) {
	vector<long long>ret(BIT);
	for (int j = 0; j < BIT; j++) {
		ret[j] = max(0LL, min((1LL << (j + 1)) - 1, R) - max(1LL << j, L) + 1);
		ret[j] %= MOD;
	}
	return ret;
}

int main() {

	int N;
	cin >> N;
	vector<long long>l(N);
	vector<long long>r(N);
	vector<long long>two(N + 1, 1);
	for (int i = 1; i <= N; i++) {
		two[i] = two[i - 1] * 2 % MOD;
	}


	//

	vector<vector<long long>>num(N, vector<long long>(BIT));
	vector<vector<long long>>mxnum(N, vector<long long>(BIT));
	for (int i = 0; i < N; i++) {
		cin >> l[i] >> r[i];
		num[i] = func1(l[i], r[i]);
		mxnum[i] = func2(l[i], r[i]);
	}

	//


	int Q;
	cin >> Q;
	long long ans = 0;
	while (Q--) {
		int k;
		cin >> k;
		if (k == 1) {
			int p;
			long long L, R;
			cin >> p >> L >> R;
			p--;
			l[p] = L;
			r[p] = R;
			num[p] = func1(l[p], r[p]);
			mxnum[p] = func2(l[p], r[p]);
			vector<Add_Segment_Tree> asg(BIT, Add_Segment_Tree(N));
			for (int i = 0; i < N; i++) {
				for (int j = 0; j < BIT; j++) {
					long long no = (r[i] - l[i] + 1) - num[i][j];
					no %= MOD;
					if (mxnum[i][j]) {
						asg[j].Mul(i, i, onoff(mxnum[i][j], 0));
					}
					else {
						asg[j].Zero(i, i);
					}
					if (i) {
						if (no == num[i][j]) {
							asg[j].MulSame(0, i - 1, no);
						}
						else {
							asg[j].Mul(0, i - 1, onoff(no, num[i][j]));
						}
					}
					if (i + 1 < N) {
						if (no == num[i][j]) {
							asg[j].MulSame(i + 1, N - 1, no);
						}
						else {
							asg[j].Mul(i + 1, N - 1, onoff(no, num[i][j]));
						}
					}
				}
			}
			ans = 0;
			for (int i = 0; i < BIT; i++) {
				ans += asg[i].Sum(0, N - 1).on;
				ans %= MOD;
			}
		}
		else {
			cout << ans << endl;
		}
	}


	return 0;
}
accuracy: 0.3157894736842105
time_ms: 1780
memory_kb: 6088
final_rank: 18

code_snippet: #include "bits/stdc++.h"

using namespace std;

constexpr long long MOD = 998244353;
constexpr int BIT = 20;

long long int gcd(long long a, long long b) {
	while (b) {
		a %= b;
		swap(a, b);
	}
	return a;
}

long long int power(long long int x, long long int n, long long int M) {
	long long int ret = 1;
	long long int by = x;
	while (n) {
		if (n & 1) {
			ret *= by;
			ret %= M;
		}
		by *= by;
		by %= M;
		n >>= 1;
	}
	return ret;
}

long long int extended_gcd(long long int a, long long int b, long long int c, long long int d, long long int m) {
	long long int ret = 0;
	if (c == 1)return d;
	ret = extended_gcd(c, d, a % c, (b + (MOD * MOD / m) * m - ((a / c) % m) * (d % m)) % m, m);
	return ret;
}

long long int extended_gcd(long long int a, long long int b) {
	long long int g = gcd(a, b);
	a /= g;
	b /= g;
	long long int box = a % b;
	long long int bag = b - (a % b);
	long long int bbox = 1;
	long long int bbag = b - 1;
	return extended_gcd(box, bbox, bag, bbag, b) * g;
}

struct onoff {
	long long on, off;
	onoff(const long long off = 1, const long long on = 1) :off(off), on(on) {

	}
	onoff operator % (const long long mod)const {
		return onoff(off % MOD, on % MOD);
	}
	void operator %= (const long long mod) {
		off %= MOD;
		on %= MOD;
	}
	onoff operator + (const onoff& o)const {
		return onoff(off + o.off, on + o.on) % MOD;
	}
	void operator += (const onoff& o) {
		off += o.off;
		if (off >= MOD)off -= MOD;
		on += o.on;
		if (on >= MOD)on -= MOD;
	}
	onoff operator * (const onoff& o)const {
		return onoff(off * o.off + on * o.on, off * o.on + on * o.off) % MOD;
	}
	onoff operator *(const long long& v)const {
		return onoff(off * v, on * v) % MOD;
	}
	void operator *= (const onoff& o) {
		long long tmp = off;
		off = on * o.on + off * o.off;
		off %= MOD;
		on = tmp * o.on + on * o.off;
		on %= MOD;
	}
	void operator *= (const long long& by) {
		on *= by;
		on %= MOD;
		off *= by;
		off %= MOD;
	}
	onoff operator /(const long long& v)const {
		long long inv = power(v, MOD - 2, MOD);
		return onoff(off * inv, on * inv) % MOD;

	}
	void Output() {
		cout << "off = " << off << " on = " << on << endl;
	}
	onoff inv() {
		long long box = off * off + MOD - on * on % MOD;
		box %= MOD;
		long long c = extended_gcd(box, MOD);
		return onoff(off * c % MOD, MOD - on * c % MOD);
	}
};

class Add_Segment_Tree {
	vector<onoff>v;
	vector<onoff>w;
	vector<int>wflag;
	vector<onoff>mul;
	vector<int>l;
	vector<int>r;
	vector<int>zero;
	int num;
	onoff ret;
	void Left(int place) {
		if (place >= v.size() / 2) {
			l[place] = place - v.size() / 2;
			return;
		}
		Left(place * 2);
		Left(place * 2 + 1);
		l[place] = l[place * 2];
		return;
	}
	void Right(int place) {
		if (place >= v.size() / 2) {
			r[place] = place - v.size() / 2;
			return;
		}
		Right(place * 2);
		Right(place * 2 + 1);
		r[place] = r[place * 2 + 1];
		return;
	}
	void Spread(int place) {
		mul[place * 2] *= mul[place];
		mul[place * 2 + 1] *= mul[place];
		mul[place] = onoff(1, 0);
	}
	void Collect(int place) {
		v[place] = onoff(0, 0);
		v[place] += v[place * 2] * mul[place * 2] * zero[place * 2] * w[place * 2];
		v[place] += v[place * 2 + 1] * mul[place * 2 + 1] * zero[place * 2 + 1] * w[place * 2 + 1];
		return;
	}
	void Mul(int a, int b, onoff o, int place) {
		if (l[place] >= a && r[place] <= b) {
			mul[place] *= o;
			return;
		}
		if (l[place] > b || r[place] < a)return;
		Spread(place);
		Mul(a, b, o, place * 2);
		Mul(a, b, o, place * 2 + 1);
		Collect(place);
		return;
	}
	void MulSame(int a, int b, long long by, int place) {
		if (l[place] >= a && r[place] <= b) {
			if (wflag[place]) {
				w[place] *= by * 2;
			}
			else {
				w[place] = onoff(by, by);
			}
			wflag[place]++;
			return;
		}
		if (l[place] > b || r[place] < a)return;
		Spread(place);
		MulSame(a, b, by, place * 2);
		MulSame(a, b, by, place * 2 + 1);
		Collect(place);
		return;
	}
	void DivSame(int a, int b, long long by, int place) {
		if (l[place] >= a && r[place] <= b) {
			wflag[place]--;
			if (wflag[place]) {
				w[place] *= by;
			}
			else {
				w[place] = onoff(1, 0);
			}
			return;
		}
		if (l[place] > b || r[place] < a)return;
		Spread(place);
		DivSame(a, b, by, place * 2);
		DivSame(a, b, by, place * 2 + 1);
		Collect(place);
		return;
	}
	void Sum(int a, int b, int place) {
		if (l[place] >= a && r[place] <= b) {
			ret += v[place] * w[place] * mul[place] * zero[place];
			return;
		}
		if (l[place] > b || r[place] < a)return;
		Spread(place);
		Sum(a, b, place * 2);
		Sum(a, b, place * 2 + 1);
		Collect(place);
		return;
	}
	void Zero(int a, int b, int place) {
		if (l[place] >= a && r[place] <= b) {
			zero[place] ^= 1;
			return;
		}
		if (l[place] > b || r[place] < a)return;
		Spread(place);
		Zero(a, b, place * 2);
		Zero(a, b, place * 2 + 1);
		Collect(place);
		return;
	}
public:
	Add_Segment_Tree(int n) {
		n++;
		num = 1;
		while (num < n * 2) {
			num *= 2;
		}
		l.resize(num);
		r.resize(num);
		zero.resize(num, 1);
		wflag.resize(num, 0);
		v.resize(num, onoff(1, 0));
		w.resize(num, onoff(1, 0));
		mul.resize(num, onoff(1, 0));
		Left(1);
		Right(1);
		for (int i = 0; i < num; i++) {
			v[i].off = r[i] - l[i] + 1;
		}
	}
	void Zero(int a, int b) {
		Zero(a, b, 1);
	}
	void Mul(int a, int b, onoff o) {
		Mul(a, b, o, 1);
	}
	void MulSame(int a, int b, long long by) {
		MulSame(a, b, by, 1);
	}
	void DivSame(int a, int b, long long by) {
		DivSame(a, b, power(by * 2, MOD - 2, MOD), 1);
	}
	onoff Sum(int a, int b) {
		ret = { 0,0 };
		Sum(a, b, 1);
		return ret;
	}
};

vector<long long>func1(long long L, long long R) {
	vector<long long>ret(BIT);
	long long by = 1;
	for (int j = 0; j < BIT; j++) {
		by <<= 1;
		long long st = L / by;
		long long ed = R / by;
		ret[j] += max(ed - st - 1, 0LL) * (by / 2);
		if (st < ed) {
			ret[j] += max(0LL, R % by - by / 2 + 1);
			ret[j] += min(by / 2, by - L % by);
		}
		else {
			ret[j] += max(0LL, R % by - by / 2 + 1);
			if (L % by) {
				ret[j] -= max(0LL, (L - 1) % by - by / 2 + 1);
			}
		}
		ret[j] %= MOD;
	}
	return ret;
}

vector<long long>func2(long long L, long long R) {
	vector<long long>ret(BIT);
	for (int j = 0; j < BIT; j++) {
		ret[j] = max(0LL, min((1LL << (j + 1)) - 1, R) - max(1LL << j, L) + 1);
		ret[j] %= MOD;
	}
	return ret;
}

int main() {

	int N;
	cin >> N;
	vector<long long>l(N);
	vector<long long>r(N);
	vector<long long>two(N + 1, 1);
	for (int i = 1; i <= N; i++) {
		two[i] = two[i - 1] * 2 % MOD;
	}


	//

	vector<vector<long long>>num(N, vector<long long>(BIT));
	vector<vector<long long>>mxnum(N, vector<long long>(BIT));
	for (int i = 0; i < N; i++) {
		cin >> l[i] >> r[i];
		num[i] = func1(l[i], r[i]);
		mxnum[i] = func2(l[i], r[i]);
	}

	//

	vector<Add_Segment_Tree> asg(BIT, Add_Segment_Tree(N));
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < BIT; j++) {
			long long no = (r[i] - l[i] + 1) - num[i][j];
			no %= MOD;
			if (mxnum[i][j]) {
				asg[j].Mul(i, i, onoff(mxnum[i][j], 0));
			}
			else {
				asg[j].Zero(i, i);
			}
			if (i) {
				if (no == num[i][j]) {
					asg[j].MulSame(0, i - 1, no);
				}
				else {
					asg[j].Mul(0, i - 1, onoff(no, num[i][j]));
				}
			}
			if (i + 1 < N) {
				if (no == num[i][j]) {
					asg[j].MulSame(i + 1, N - 1, no);
				}
				else {
					asg[j].Mul(i + 1, N - 1, onoff(no, num[i][j]));
				}
			}
		}
	}

	int Q;
	cin >> Q;
	while (Q--) {
		int k;
		cin >> k;
		if (k == 1) {
			int p;
			long long L, R;
			cin >> p >> L >> R;
			p--;

			for (int i = 0; i < BIT; i++) {
				if (mxnum[p][i]) {
					asg[i].Mul(p, p, onoff(mxnum[p][i], 0).inv());
				}
				else {
					asg[i].Zero(p, p);
				}
				long long no = r[p] - l[p] + 1 - num[p][i];
				no %= MOD;
				if (p) {
					if (no == num[p][i]) {
						asg[i].DivSame(0, p - 1, no);
					}
					else {
						asg[i].Mul(0, p - 1, onoff(no, num[p][i]).inv());
					}
				}
				if (p + 1 < N) {
					if (no == num[p][i]) {
						asg[i].DivSame(p + 1, N - 1, no);
					}
					else {
						asg[i].Mul(p + 1, N - 1, onoff(no, num[p][i]).inv());
					}
				}
			}

			l[p] = L;
			r[p] = R;

			num[p] = func1(l[p], r[p]);
			mxnum[p] = func2(l[p], r[p]);

			for (int i = 0; i < BIT; i++) {
				if (mxnum[p][i]) {
					asg[i].Mul(p, p, onoff(mxnum[p][i], 0));
				}
				else {
					asg[i].Zero(p, p);
				}
				long long no = r[p] - l[p] + 1 - num[p][i];
				no %= MOD;
				if (p) {
					if (no == num[p][i]) {
						asg[i].MulSame(0, p - 1, no);
					}
					else {
						asg[i].Mul(0, p - 1, onoff(no, num[p][i]));
					}
				}
				if (p + 1 < N) {
					if (no == num[p][i]) {
						asg[i].MulSame(p + 1, N - 1, no);
					}
					else {
						asg[i].Mul(p + 1, N - 1, onoff(no, num[p][i]));
					}
				}
			}
		}
		else {
			long long ans = 0;
			for (int i = 0; i < BIT; i++) {
				ans += asg[i].Sum(0, N - 1).on;
				ans %= MOD;
			}
			cout << ans << endl;
		}
	}


	return 0;
}
accuracy: 1
time_ms: 190
memory_kb: 15368
final_rank: 7