Problem:
Problem J: Ukunichia Query

Problem

$N$ 人の人が左から右へ一列に並んでいる。彼らの間では文字列 $S$ が流行している。

各人は、以下の条件を満たすとき幸せであり、そうでないとき幸せではない。

今までに $|S|$ 文字以上の文字を伝えられていて、かつ直近の $|S|$ 文字を古い順から新しい順に並べると $S$ と一致する

以下の $2$ 種類のクエリを合計 $Q$ 回処理せよ。

クエリ1

$1$ $l$ $r$ $c$

区間 $[l, r]$ に含まれる人に文字列 $c$ を左から一文字ずつ伝える。

クエリ2

$2$ $l$ $r$

区間 $[l, r]$ に含まれる幸せな人の数を求める。

ただし、区間 $[l, r]$ とは、左から $l$ 番目から $r$ 番目までの人のことを表す。

Input

入力は以下の形式で与えられる。

$S$
$N$ $Q$
$query_1$
$\vdots$
$query_Q$

$1$ 行目に流行している文字列 $S$ が与えられる。

$2$ 行目に並んでいる人の数 $N$ とクエリの数 $Q$ が空白区切りで与えられる。

$3$ 行目から続く $Q$ 行にクエリの情報が与えられる。

Constraints

入力は以下の条件を満たす。

$1 \leq |S| \leq 20 $

$1 \leq N \leq 10^5 $

$1 \leq Q \leq 10^5 $

$1 \leq l \leq r \leq N$

$1 \leq |c| \leq 10 $

$S, c$ は英小文字からなる

各クエリはクエリ1かクエリ2のいずれかである

クエリ2が必ず一つ以上含まれる

Output

各クエリ2について、幸せな人の数を1行に出力せよ。

Sample Input 1

abab
5 5
2 2 4
1 1 5 abab
2 3 5
1 3 3 a
2 1 5

Sample Output 1

0
3
4

Sample Input 2

uku
1333 5
2 232 423
1 13 532 uku
2 322 567
1 3 33 ku
2 1 333

Sample Output 2

0
211
321

Sample Input 3

aabb
1879 20
2 69 1585
1 415 1680 aabb
1 756 1628 abbabbaa
1 849 1273 abba
2 418 1172
2 1063 1164
2 203 623
2 481 1209
1 107 110 ababaaaab
1 857 985 bbbbabbbaa
1 868 947 aaa
1 1619 1789 aabab
2 204 844
2 493 1422
2 821 1499
1 757 1817 abbabbb
2 232 911
1 653 797 aaabaaaab
2 701 1657
1 868 940 aaabbbaaa

Sample Output 3

0
338
0
209
275
341
263
0
341
0

Solution in C++14 (judge verdict: Accepted)

// う？笑
#include <bits/stdc++.h>

using namespace std;

using int64 = long long;
const int mod = 1e9 + 7;

const int64 infll = (1LL << 62) - 1;
const int inf = (1 << 30) - 1;

struct IoSetup {
  IoSetup() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(10);
    cerr << fixed << setprecision(10);
  }
} iosetup;


template< typename T1, typename T2 >
ostream &operator<<(ostream &os, const pair< T1, T2 > &p) {
  os << p.first << " " << p.second;
  return os;
}

template< typename T1, typename T2 >
istream &operator>>(istream &is, pair< T1, T2 > &p) {
  is >> p.first >> p.second;
  return is;
}

template< typename T >
ostream &operator<<(ostream &os, const vector< T > &v) {
  for(int i = 0; i < (int) v.size(); i++) {
    os << v[i] << (i + 1 != v.size() ? " " : "");
  }
  return os;
}

template< typename T >
istream &operator>>(istream &is, vector< T > &v) {
  for(T &in : v) is >> in;
  return is;
}

template< typename T1, typename T2 >
inline bool chmax(T1 &a, T2 b) { return a < b && (a = b, true); }

template< typename T1, typename T2 >
inline bool chmin(T1 &a, T2 b) { return a > b && (a = b, true); }

template< typename T = int64 >
vector< T > make_v(size_t a) {
  return vector< T >(a);
}

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

template< typename T, typename V >
typename enable_if< is_class< T >::value == 0 >::type fill_v(T &t, const V &v) {
  t = v;
}

template< typename T, typename V >
typename enable_if< is_class< T >::value != 0 >::type fill_v(T &t, const V &v) {
  for(auto &e : t) fill_v(e, v);
}

template< typename F >
struct FixPoint : F {
  FixPoint(F &&f) : F(forward< F >(f)) {}

  template< typename... Args >
  decltype(auto) operator()(Args &&... args) const {
    return F::operator()(*this, forward< Args >(args)...);
  }
};

template< typename F >
inline decltype(auto) MFP(F &&f) {
  return FixPoint< F >{forward< F >(f)};
}

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;
  }
};

template< int char_size >
struct TrieNode {
  int nxt[char_size];

  int exist;
  vector< int > accept;

  TrieNode() : exist(0) {
    memset(nxt, -1, sizeof(nxt));
  }
};

template< int char_size, int margin >
struct Trie {
  using Node = TrieNode< char_size >;

  vector< Node > nodes;
  int root;

  Trie() : root(0) {
    nodes.push_back(Node());
  }

  void update_direct(int node, int id) {
    nodes[node].accept.push_back(id);
  }

  void update_child(int node, int child, int id) {
    ++nodes[node].exist;
  }

  void add(const string &str, int str_index, int node_index, int id) {
    if(str_index == str.size()) {
      update_direct(node_index, id);
    } else {
      const int c = str[str_index] - margin;
      if(nodes[node_index].nxt[c] == -1) {
        nodes[node_index].nxt[c] = (int) nodes.size();
        nodes.push_back(Node());
      }
      add(str, str_index + 1, nodes[node_index].nxt[c], id);
      update_child(node_index, nodes[node_index].nxt[c], id);
    }
  }

  void add(const string &str, int id) {
    add(str, 0, 0, id);
  }

  void add(const string &str) {
    add(str, nodes[0].exist);
  }

  void query(const string &str, const function< void(int) > &f, int str_index, int node_index) {
    for(auto &idx : nodes[node_index].accept) f(idx);
    if(str_index == str.size()) {
      return;
    } else {
      const int c = str[str_index] - margin;
      if(nodes[node_index].nxt[c] == -1) return;
      query(str, f, str_index + 1, nodes[node_index].nxt[c]);
    }
  }

  void query(const string &str, const function< void(int) > &f) {
    query(str, f, 0, 0);
  }

  int count() const {
    return (nodes[0].exist);
  }

  int size() const {
    return ((int) nodes.size());
  }
};


template< int char_size, int margin >
struct AhoCorasick : Trie< char_size + 1, margin > {
  using Trie< char_size + 1, margin >::Trie;

  const int FAIL = char_size;
  vector< int > correct;

  void build(bool heavy = true) {
    correct.resize(this->size());
    for(int i = 0; i < this->size(); i++) {
      correct[i] = (int) this->nodes[i].accept.size();
    }
    queue< int > que;
    for(int i = 0; i <= char_size; i++) {
      if(~this->nodes[0].nxt[i]) {
        this->nodes[this->nodes[0].nxt[i]].nxt[FAIL] = 0;
        que.emplace(this->nodes[0].nxt[i]);
      } else {
        this->nodes[0].nxt[i] = 0;
      }
    }
    while(!que.empty()) {
      auto &now = this->nodes[que.front()];
      correct[que.front()] += correct[now.nxt[FAIL]];
      que.pop();
      for(int i = 0; i < char_size; i++) {
        if(now.nxt[i] == -1) continue;
        int fail = now.nxt[FAIL];
        while(this->nodes[fail].nxt[i] == -1) fail = this->nodes[fail].nxt[FAIL];
        this->nodes[now.nxt[i]].nxt[FAIL] = this->nodes[fail].nxt[i];
        if(heavy) {
          auto &u = this->nodes[now.nxt[i]].accept;
          auto &v = this->nodes[this->nodes[fail].nxt[i]].accept;
          vector< int > accept;
          set_union(begin(u), end(u), begin(v), end(v), back_inserter(accept));
          u = accept;
        }
        que.emplace(now.nxt[i]);
      }

    }
  }

  map< int, int > match(const string &str, int now = 0) {
    map< int, int > result;
    for(auto &c : str) {
      while(this->nodes[now].nxt[c - margin] == -1) now = this->nodes[now].nxt[FAIL];
      now = this->nodes[now].nxt[c - margin];
      for(auto &v : this->nodes[now].accept) result[v] += 1;
    }
    return result;
  }

  pair< int, int > move(const char &c, int now) {
    int sum = 0;
    while(this->nodes[now].nxt[c - margin] == -1) now = this->nodes[now].nxt[FAIL];
    now = this->nodes[now].nxt[c - margin];
    sum += correct[now];
    return {sum, now};
  }
};

int main() {
  string S;
  cin >> S;
  int N, Q;
  cin >> N >> Q;

  AhoCorasick< 26, 'a' > aho;
  aho.add(S);
  aho.build();

  using vi = array< int, 22 >;
  vi e{0};

  auto f = [](vi a, const vi &b) {
    for(int i = 0; i < 22; i++) a[i] += b[i];
    return a;
  };
  auto g = [&](const vi &a, const string &s) {
    vi b{0};
    for(int i = 0; i < 22; i++) {
      if(a[i] > 0) {
        int cur = i;
        for(auto &c : s) cur = aho.move(c, cur).second;
        b[cur] += a[i];
      }
    }
    return b;
  };
  auto h = [&](string a, string b) {
    reverse(begin(b), end(b));
    reverse(begin(a), end(a));
    b += a;
    if(a.size() > S.size()) b.resize(S.size());
    reverse(begin(b), end(b));
    return b;
  };


  LazySegmentTree< vi, string > seg(N, f, g, h, e, string());
  e[0] = 1;
  for(int i = 0; i < N; i++) seg.set(i, e);
  e[0] = 0;
  seg.build();

  while(Q--) {
    int T, L, R;
    cin >> T >> L >> R;
    --L;
    if(T == 1) {
      string C;
      cin >> C;
      seg.update(L, R, C);
    } else {
      auto ret = seg.query(L, R);
      int latte = 0;
      for(int i = 0; i < 22; i++) {
        if(ret[i] > 0 && aho.correct[i]) latte += ret[i];
      }
      cout << latte << endl;
    }
  }
}