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

Submitted solutions:

code_snippet: #include<bits/stdc++.h>
#include<array>
using namespace std;
using UL = unsigned int;
using ULL = unsigned long long;
using LL = long long;
#define rep(i,n) for(int i=0; i<(n); i++)

struct VRSQ{
 int M[21];
 int V[21];
 bool z;
 VRSQ(){
  rep(i,21){ M[i]=i; V[i]=0; z=false; }
 }
 VRSQ wrap(const VRSQ& inner){
  VRSQ ans;
  rep(i,21){
   ans.V[M[i]] += inner.V[i];
   ans.M[i] = M[inner.M[i]];
  }
  return ans;
 }
 VRSQ operator+(const VRSQ& r) const {
  VRSQ ans;
  rep(i,21) ans.V[i] = V[i] + r.V[i];
  return ans;
 }
};

struct RSQ{
 int N;
 vector<VRSQ> V;
 void init(int n){
  N=1; while(N<n) N<<=1;
  V.resize(N*2);
  rep(i,n) V[i+N].V[0]=1;
  for(int i=N-1; i>=1; i--)
   V[i] = V[i].wrap(V[i<<1]+V[(i<<1)+1]);
 }
 void expand(int i){
  if(!V[i].z) return;
  V[i<<1] = V[i].wrap(V[i<<1]); V[i<<1].z=true;
  V[(i<<1)+1] = V[i].wrap(V[(i<<1)+1]); V[(i<<1)+1].z=true;
  rep(j,21) V[i].M[j]=j; V[i].z=false;
 }
 void upd(int l,int r,VRSQ x,int a=-1,int b=-1,int i=-1){
  if(i==-1){ a=0; b=N; i=1; }
  if(r<=a || b<=l) return;
  if(l<=a && b<=r){ V[i] = x.wrap(V[i]); V[i].z=true; return; }
  expand(i);
  upd(l,r,x,a,(a+b)>>1,i<<1);
  upd(l,r,x,(a+b)>>1,b,(i<<1)+1);
  V[i] = V[i].wrap(V[i<<1]+V[(i<<1)+1]);
 }
 VRSQ query(int l,int r,int a=-1,int b=-1,int i=-1){
  if(i==-1){ a=0; b=N; i=1; }
  if(r<=a || b<=l) return VRSQ{};
  if(l<=a && b<=r) return V[i];
  expand(i);
  auto q1 = query(l,r,a,(a+b)>>1,i<<1);
  auto q2 = query(l,r,(a+b)>>1,b,(i<<1)+1);
  return V[i].wrap(q1+q2);
 }
};

string S;
int N,Q;
RSQ G;

VRSQ X[26];

int main() {
 cin>>S;
 scanf("%d%d",&N,&Q);
 G.init(N);
 rep(i,21)rep(c,26) X[c].M[i]=0;
 rep(i,S.size()+1)rep(c,26){
  string tg = S.substr(0,i) + char('a'+c);
  rep(j,min(tg.size()+1,S.size()+1)){
   if(tg.substr(tg.size()-j,j) == S.substr(0,j)) X[c].M[i] = j;
  }
 }
 rep(i,Q){
  int c; scanf("%d",&c);
  if(c==1){
   int l,r; scanf("%d%d",&l,&r); l--;
   string C; cin>>C;
   VRSQ buf;
   for(char cC:C) buf = X[cC-'a'].wrap(buf);
   G.upd(l,r,buf);
  }
  if(c==2){
   int l,r; scanf("%d%d",&l,&r); l--;
   auto q = G.query(l,r);
   printf("%d\n",G.query(l,r).V[S.size()]);
  }
 }
 return 0;
}
accuracy: 1
time_ms: 800
memory_kb: 47132
final_rank: 3

code_snippet: // う？笑
#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;
    }
  }
}
accuracy: 1
time_ms: 2410
memory_kb: 43464
final_rank: 8

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 500005

int N = 1;
int LEN;
int num[SIZE][25],table[SIZE][25];
int shift[25],num_work[25];
int next_loc[25][26];
bool have_info[SIZE];
char S[25],work[25];


void init(int first_N){
	while(N < first_N)N *= 2;
}

void update_first(int loc){

	loc += N-1;

	num[loc][0] = 1;

	if(N == 1)return;

	int parent = (loc-1)/2;

	while(true){
		num[parent][0] = num[2*parent+1][0]+num[2*parent+2][0];

		if(parent == 0)break;
		else{
			parent = (parent-1)/2;
		}
	}
}

void calc(int node_id){

	for(int i = 0; i <= LEN; i++){

		num_work[i] = 0;
	}
	for(int i = 0; i <= LEN; i++){

		num_work[table[node_id][i]] += num[node_id][i];
	}
	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num_work[i];
	}
}

void update(int search_left,int search_right,int node_id,int node_left,int node_right){

	int left_child = 2*node_id+1;
	int right_child = 2*node_id+2;

	if(have_info[node_id]){

		calc(node_id);

		if(node_left < node_right){

			for(int i = 0; i <= LEN; i++){

				table[left_child][i] = table[node_id][table[left_child][i]];
				table[right_child][i] = table[node_id][table[right_child][i]];
			}
			have_info[left_child] = true;
			have_info[right_child] = true;
		}
		for(int i = 0; i <= LEN; i++){
			table[node_id][i] = i;
		}
		have_info[node_id] = false;
	}

	if(search_right < node_left || search_left > node_right)return;

	if(search_left <= node_left && search_right >= node_right){

		for(int i = 0; i <= LEN; i++){

			table[node_id][i] = shift[table[node_id][i]];
		}

		calc(node_id);

		if(node_left < node_right){

			for(int i = 0; i <= LEN; i++){

				table[left_child][i] = table[node_id][table[left_child][i]];
				table[right_child][i] = table[node_id][table[right_child][i]];
			}
			have_info[left_child] = true;
			have_info[right_child] = true;
		}

		for(int i = 0; i <= LEN; i++){
			table[node_id][i] = i;
		}
		return;
	}
	update(search_left,search_right,left_child,node_left,(node_left+node_right)/2);
	update(search_left,search_right,right_child,(node_left+node_right)/2+1,node_right);

	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num[left_child][i]+num[right_child][i];
	}
}

int query(int search_left,int search_right,int node_id,int node_left,int node_right){

	int left_child = 2*node_id+1;
	int right_child = 2*node_id+2;

	if(have_info[node_id]){

		calc(node_id);

		if(node_left < node_right){

			for(int i = 0; i <= LEN; i++){

				table[left_child][i] = table[node_id][table[left_child][i]];
				table[right_child][i] = table[node_id][table[right_child][i]];
			}
			have_info[left_child] = true;
			have_info[right_child] = true;
		}
		for(int i = 0; i <= LEN; i++){
			table[node_id][i] = i;
		}
		have_info[node_id] = false;
	}

	if(search_right < node_left || search_left > node_right){
		return 0;
	}

	if(search_left <= node_left && search_right >= node_right){

		return num[node_id][LEN];
	}

	int left = query(search_left,search_right,left_child,node_left,(node_left+node_right)/2);
	int right =  query(search_left,search_right,right_child,(node_left+node_right)/2+1,node_right);

	return left+right;
}

int main(){

	scanf("%s",S);

	for(LEN = 0; S[LEN] != '\0'; LEN++);

	int index,head,max_match_len;

	for(int len = 0; len <= LEN; len++){
		for(index = 0; index < len; index++){

			work[index] = S[index];
		}
		for(int ch = 0; ch < 26; ch++){

			work[index] = 'a'+ch;

			if(len == LEN){

				head = 1;
			}else{

				head = 0;
			}

			max_match_len = 0;

			for(int i = head; i <= index; i++){

				bool FLG = true;
				for(int k = i; k <= index; k++){
					if(work[k] != S[k-i]){

						FLG = false;
						break;
					}
				}
				if(FLG){
					max_match_len = index-i+1;
					break;
				}
			}
			next_loc[len][ch] = max_match_len;
		}
	}

	int first_N,num_query;
	scanf("%d %d",&first_N,&num_query);

	init(first_N);

	for(int i = 0; i <= 2*N-2; i++){
		have_info[i] = false;
		for(int k = 0; k <= LEN; k++){
			num[i][k] = 0;
			table[i][k] = k;
		}
	}

	for(int i = 0; i < first_N; i++){

		update_first(i);
	}

	int command,left,right;

	for(int i = 0; i < num_query; i++){
		scanf("%d",&command);

		if(command == 2){

			scanf("%d %d",&left,&right);
			left--;
			right--;

			printf("%d\n",query(left,right,0,0,N-1));

		}else{
			scanf("%d %d %s",&left,&right,work);
			left--;
			right--;

			for(int k = 0; k <= LEN; k++){

				shift[k] = k;
			}
			for(int a = 0; work[a] != '\0'; a++){
				for(int k = 0; k <= LEN; k++){

					shift[k] = next_loc[shift[k]][work[a]-'a'];
				}
			}

			update(left,right,0,0,N-1);
		}
	}
	return 0;
}
accuracy: 1
time_ms: 650
memory_kb: 54696
final_rank: 4

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 500005

int N = 1;
int LEN;
int num[SIZE][25],table[SIZE][25];
int shift[25],num_work[25];
int next_loc[25][26];
bool have_info[SIZE];
char S[25],work[25];


void init(int first_N){
	while(N < first_N)N *= 2;
}

void update_first(int loc){

	loc += N-1;

	num[loc][0] = 1;

	if(N == 1)return;

	int parent = (loc-1)/2;

	while(true){
		num[parent][0] = num[2*parent+1][0]+num[2*parent+2][0];

		if(parent == 0)break;
		else{
			parent = (parent-1)/2;
		}
	}
}

void calc(int node_id){

	for(int i = 0; i <= LEN; i++){

		num_work[i] = 0;
	}
	for(int i = 0; i <= LEN; i++){

		num_work[table[node_id][i]] += num[node_id][i];
	}
	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num_work[i];
	}
}

void update(int search_left,int search_right,int node_id,int node_left,int node_right){

	int left_child = 2*node_id+1;
	int right_child = 2*node_id+2;

	if(have_info[node_id]){

		calc(node_id);

		if(node_left < node_right){

			for(int i = 0; i <= LEN; i++){

				table[left_child][i] = table[node_id][table[left_child][i]];
				table[right_child][i] = table[node_id][table[right_child][i]];
			}
			have_info[left_child] = true;
			have_info[right_child] = true;
		}
		for(int i = 0; i <= LEN; i++){

			table[node_id][i] = i;
		}
		have_info[node_id] = false;
	}

	if(search_right < node_left || search_left > node_right)return;

	if(search_left <= node_left && search_right >= node_right){

		for(int i = 0; i <= LEN; i++){

			table[node_id][i] = shift[table[node_id][i]];
		}

		calc(node_id);


		if(node_left < node_right){

			for(int i = 0; i <= LEN; i++){

				table[left_child][i] = table[node_id][table[left_child][i]];
				table[right_child][i] = table[node_id][table[right_child][i]];
			}
			have_info[left_child] = true;
			have_info[right_child] = true;
		}
		for(int i = 0; i <= LEN; i++){

			table[node_id][i] = i;
		}
		have_info[node_id] = false;

		return;
	}

	update(search_left,search_right,left_child,node_left,(node_left+node_right)/2);
	update(search_left,search_right,right_child,(node_left+node_right)/2+1,node_right);

	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num[left_child][i]+num[right_child][i];
	}
}

int query(int search_left,int search_right,int node_id,int node_left,int node_right){

	int left_child = 2*node_id+1;
	int right_child = 2*node_id+2;

	if(have_info[node_id]){

		calc(node_id);

		if(node_left < node_right){

			for(int i = 0; i <= LEN; i++){

				table[left_child][i] = table[node_id][table[left_child][i]];
				table[right_child][i] = table[node_id][table[right_child][i]];
			}
			have_info[left_child] = true;
			have_info[right_child] = true;
		}

		for(int i = 0; i <= LEN; i++){

			table[node_id][i] = i;
		}
		have_info[node_id] = false;
	}


	if(search_right < node_left || search_left > node_right)return 0;

	if(search_left <= node_left && search_right >= node_right){

		return num[node_id][LEN];
	}

	int left = query(search_left,search_right,left_child,node_left,(node_left+node_right)/2);
	int right =  query(search_left,search_right,right_child,(node_left+node_right)/2+1,node_right);

	return left+right;
}

int main(){

	scanf("%s",S);

	for(LEN = 0; S[LEN] != '\0'; LEN++);

	int index,head,max_match_len;

	//len文字一致している状態から、次に文字chが来た時、何文字一致した状態に写るかを計算
	for(int len = 0; len <= LEN; len++){
		for(index = 0; index < len; index++){

			work[index] = S[index];
		}
		for(int ch = 0; ch < 26; ch++){

			work[index] = 'a'+ch;

			if(len == LEN){

				head = 1;
			}else{

				head = 0;
			}

			max_match_len = 0;

			for(int i = head; i <= index; i++){

				bool FLG = true;
				for(int k = i; k <= index; k++){
					if(work[k] != S[k-i]){

						FLG = false;
						break;
					}
				}
				if(FLG){
					max_match_len = index-i+1;
					break;
				}
			}
			next_loc[len][ch] = max_match_len;
		}
	}

	int first_N,num_query;
	scanf("%d %d",&first_N,&num_query);

	init(first_N);

	for(int i = 0; i <= 2*N-2; i++){
		have_info[i] = false;
		for(int k = 0; k <= LEN; k++){
			num[i][k] = 0; //ノードiのカバー範囲において、Sとk文字一致しているノードがいくつあるか
			table[i][k] = k; //最初kにあったマッチ長が、現在どのマッチ位置に遷移しているか
		}
	}

	for(int i = 0; i < first_N; i++){

		update_first(i);
	}

	int command,left,right;

	for(int i = 0; i < num_query; i++){
		scanf("%d",&command);

		if(command == 2){

			scanf("%d %d",&left,&right);
			left--;
			right--;

			printf("%d\n",query(left,right,0,0,N-1));

		}else{
			scanf("%d %d %s",&left,&right,work);
			left--;
			right--;

			for(int k = 0; k <= LEN; k++){

				shift[k] = k;
			}
			for(int a = 0; work[a] != '\0'; a++){
				for(int k = 0; k <= LEN; k++){

					shift[k] = next_loc[shift[k]][work[a]-'a'];
				}
			}

			update(left,right,0,0,N-1);
		}
	}
	return 0;
}
accuracy: 1
time_ms: 620
memory_kb: 54652
final_rank: 2

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 500005

int N = 1;
int LEN;
int num[SIZE][25],table[SIZE][25];
int shift[25],num_work[25];
int next_loc[25][26];
bool need_calc[SIZE],have_info[SIZE];
char S[25],work[25];


void init(int first_N){
	while(N < first_N)N *= 2;
}

void update_first(int loc){

	loc += N-1;

	num[loc][0] = 1;

	if(N == 1)return;

	int parent = (loc-1)/2;

	while(true){
		num[parent][0] = num[2*parent+1][0]+num[2*parent+2][0];

		if(parent == 0)break;
		else{
			parent = (parent-1)/2;
		}
	}
}

void calc(int node_id){

	//printf("calc:%d\n",node_id);

	for(int i = 0; i <= LEN; i++){

		num_work[i] = 0;
	}
	for(int i = 0; i <= LEN; i++){

		num_work[table[node_id][i]] += num[node_id][i];
	}
	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num_work[i];
		//printf("num[%d][%d]:%d\n",node_id,i,num[node_id][i]);
	}
}

void update(int search_left,int search_right,int node_id,int node_left,int node_right){

	if(need_calc[node_id]){

		calc(node_id);
		have_info[node_id] = true;
		need_calc[node_id] = false;
	}

	if(search_right < node_left || search_left > node_right)return;

	if(search_left <= node_left && search_right >= node_right){

		//printf("node_id:%d 部分区間内\n",node_id);

		for(int i = 0; i <= LEN; i++){

			table[node_id][i] = shift[table[node_id][i]];
		}

		calc(node_id);

		have_info[node_id] = true; //子に伝えていない遷移表を持っている

		/*printf("遷移表\n");
		for(int i = 0; i <= LEN; i++){

			printf("位置%d %d\n",i,table[node_id][i]);
		}
		printf("個数\n");
		for(int i = 0; i <= LEN; i++){

			printf("位置%d 個数:%d\n",i,num[node_id][i]);
		}*/

		return;
	}


	int left_child = 2*node_id+1;
	int right_child = 2*node_id+2;

	/*printf("node_id:%d node_left:%d node_right:%d 一様性が壊れたので、%d と %dに以下の情報を伝達\n",node_id,node_left,node_right,left_child,right_child);
	for(int i = 0; i <= LEN; i++){

		printf("位置%d: %d\n",i,table[node_id][i]);
	}*/

	if(have_info[node_id]){ //子に伝えていない遷移情報を持っている場合

		for(int i = 0; i <= LEN; i++){

			table[left_child][i] = table[node_id][table[left_child][i]];
			table[right_child][i] = table[node_id][table[right_child][i]];
		}
		need_calc[left_child] = true;
		need_calc[right_child] = true;
		have_info[node_id] = false;

		//子に遷移情報を伝えたので遷移表初期化
		for(int i = 0; i <= LEN; i++){

			table[node_id][i] = i;
		}
	}

	update(search_left,search_right,left_child,node_left,(node_left+node_right)/2);
	update(search_left,search_right,right_child,(node_left+node_right)/2+1,node_right);

	//集計
	/*
	 * 部分updateでは全体の値が変わるので集計しなおす
	 *
	 * */
	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num[left_child][i]+num[right_child][i];
		//printf("num[%d][%d]:%d\n",node_id,i,num[node_id][i]);
	}
}

int query(int search_left,int search_right,int node_id,int node_left,int node_right){

	if(need_calc[node_id]){ //遷移表が更新された場合

		calc(node_id);
		have_info[node_id] = true;
		need_calc[node_id] = false;
	}

	if(search_right < node_left || search_left > node_right)return 0;

	if(search_left <= node_left && search_right >= node_right){

		//printf("node_id:%d 部分区間内\n",node_id);
		return num[node_id][LEN];
	}

	//旧情報伝達
	int left_child = 2*node_id+1;
	int right_child = 2*node_id+2;

	/*printf("node_id:%d node_left:%d node_right:%d 一様性が壊れたので、%d と %dに以下の情報を伝達\n",node_id,node_left,node_right,left_child,right_child);
	for(int i = 0; i <= LEN; i++){

		printf("位置%d: %d\n",i,table[node_id][i]);
	}*/

	if(have_info[node_id]){ //子に伝えていない遷移情報を持っている場合

		/*
		 * 部分区間情報を正確に拾うために情報を伝播
		 * */
		for(int i = 0; i <= LEN; i++){

			table[left_child][i] = table[node_id][table[left_child][i]];
			table[right_child][i] = table[node_id][table[right_child][i]];
		}
		need_calc[left_child] = true;
		need_calc[right_child] = true;
		have_info[node_id] = false;

		//遷移表初期化
		for(int i = 0; i <= LEN; i++){

			table[node_id][i] = i;
		}
	}

	int left = query(search_left,search_right,left_child,node_left,(node_left+node_right)/2);
	int right =  query(search_left,search_right,right_child,(node_left+node_right)/2+1,node_right);

	/*
	 * 子に伝えていない遷移情報を持っている→区間全体は集計済、
	 * 持っていない→update時に集計済で、いずれにせよ区間全体の総数は変わらないので
	 * 集計し直しは不要。
	 *
	 * */

	return left+right;
}

int main(){

	scanf("%s",S);

	for(LEN = 0; S[LEN] != '\0'; LEN++);

	int index,head,max_match_len;

	//len文字一致している状態から、次に文字chが来た時、何文字一致した状態に写るかを計算
	for(int len = 0; len <= LEN; len++){
		for(index = 0; index < len; index++){

			work[index] = S[index];
		}
		for(int ch = 0; ch < 26; ch++){

			work[index] = 'a'+ch;

			if(len == LEN){

				head = 1;
			}else{

				head = 0;
			}

			max_match_len = 0;

			for(int i = head; i <= index; i++){

				bool FLG = true;
				for(int k = i; k <= index; k++){
					if(work[k] != S[k-i]){

						FLG = false;
						break;
					}
				}
				if(FLG){
					max_match_len = index-i+1;
					break;
				}
			}
			next_loc[len][ch] = max_match_len;
			//printf("next_loc[%d][%d]:%d\n",len,ch,next_loc[len][ch]);
		}
	}

	int first_N,num_query;
	scanf("%d %d",&first_N,&num_query);

	init(first_N);

	//printf("N:%d\n",N);

	for(int i = 0; i <= 2*N-2; i++){
		need_calc[i] = false;
		have_info[i] = false;
		for(int k = 0; k <= LEN; k++){
			num[i][k] = 0; //ノードiのカバー範囲において、Sとk文字一致しているノードがいくつあるか
			table[i][k] = k; //最初kにあったマッチ長が、現在どのマッチ位置に遷移しているか
		}
	}

	for(int i = 0; i < first_N; i++){

		update_first(i);
	}

	int command,left,right;

	for(int i = 0; i < num_query; i++){
		scanf("%d",&command);

		if(command == 2){

			scanf("%d %d",&left,&right);
			left--;
			right--;

			printf("%d\n",query(left,right,0,0,N-1));

		}else{
			scanf("%d %d %s",&left,&right,work);
			left--;
			right--;

			for(int k = 0; k <= LEN; k++){

				shift[k] = k;
			}
			for(int a = 0; work[a] != '\0'; a++){
				for(int k = 0; k <= LEN; k++){

					shift[k] = next_loc[shift[k]][work[a]-'a'];
				}
			}

			/*for(int k = 0; k <= LEN; k++){

				printf("shift[%d]:%d\n",k,shift[k]);
			}*/

			//continue;

			update(left,right,0,0,N-1);
		}
	}
	return 0;
}
accuracy: 0.7777777777777778
time_ms: 200
memory_kb: 54872
final_rank: 11

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 500005

int N = 1;
int LEN;
int num[SIZE][25],table[SIZE][25];
int shift[25],num_work[25];
int next_loc[25][26];
bool need_calc[SIZE],have_info[SIZE];
char S[25],work[25];


void init(int first_N){
	while(N < first_N)N *= 2;
}

void update_first(int loc){

	loc += N-1;

	num[loc][0] = 1;

	if(N == 1)return;

	int parent = (loc-1)/2;

	while(true){
		num[parent][0] = num[2*parent+1][0]+num[2*parent+2][0];

		if(parent == 0)break;
		else{
			parent = (parent-1)/2;
		}
	}
}

void calc(int node_id){

	//printf("calc:%d\n",node_id);

	for(int i = 0; i <= LEN; i++){

		num_work[i] = 0;
	}
	for(int i = 0; i <= LEN; i++){

		num_work[table[node_id][i]] += num[node_id][i];
	}
	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num_work[i];
		//printf("num[%d][%d]:%d\n",node_id,i,num[node_id][i]);
	}
}

void update(int search_left,int search_right,int node_id,int node_left,int node_right){

	if(need_calc[node_id]){

		calc(node_id);
		have_info[node_id] = true;
		need_calc[node_id] = false;
	}

	if(search_right < node_left || search_left > node_right)return;

	if(search_left <= node_left && search_right >= node_right){

		//printf("node_id:%d 部分区間内\n",node_id);

		for(int i = 0; i <= LEN; i++){

			num_work[i] = 0;
		}

		for(int i = 0; i <= LEN; i++){

			int next = shift[table[node_id][i]];

			num_work[next] += num[node_id][i];
			table[node_id][i] = next; //遷移表を更新する
		}
		for(int i = 0; i <= LEN; i++){

			num[node_id][i] = num_work[i];
		}

		have_info[node_id] = true; //子に伝えていない遷移表を持っている

		/*printf("遷移表\n");
		for(int i = 0; i <= LEN; i++){

			printf("位置%d %d\n",i,table[node_id][i]);
		}
		printf("個数\n");
		for(int i = 0; i <= LEN; i++){

			printf("位置%d 個数:%d\n",i,num[node_id][i]);
		}*/

		return;
	}


	int left_child = 2*node_id+1;
	int right_child = 2*node_id+2;

	/*printf("node_id:%d node_left:%d node_right:%d 一様性が壊れたので、%d と %dに以下の情報を伝達\n",node_id,node_left,node_right,left_child,right_child);
	for(int i = 0; i <= LEN; i++){

		printf("位置%d: %d\n",i,table[node_id][i]);
	}*/

	if(have_info[node_id]){ //子に伝えていない遷移情報を持っている場合

		for(int i = 0; i <= LEN; i++){

			table[left_child][i] = table[node_id][table[left_child][i]];
			table[right_child][i] = table[node_id][table[right_child][i]];
		}
		need_calc[left_child] = true;
		need_calc[right_child] = true;
		have_info[node_id] = false;
	}

	update(search_left,search_right,left_child,node_left,(node_left+node_right)/2);
	update(search_left,search_right,right_child,(node_left+node_right)/2+1,node_right);

	//集計
	//printf("\n");
	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num[left_child][i]+num[right_child][i];
		//printf("num[%d][%d]:%d\n",node_id,i,num[node_id][i]);
	}

	//遷移表初期化
	for(int i = 0; i <= LEN; i++){

		table[node_id][i] = i;
	}
}

int query(int search_left,int search_right,int node_id,int node_left,int node_right){

	if(need_calc[node_id]){ //遷移表が更新された場合

		calc(node_id);
		have_info[node_id] = true;
		need_calc[node_id] = false;
	}

	if(search_right < node_left || search_left > node_right)return 0;

	if(search_left <= node_left && search_right >= node_right){

		//printf("node_id:%d 部分区間内\n",node_id);
		return num[node_id][LEN];
	}

	//旧情報伝達
	int left_child = 2*node_id+1;
	int right_child = 2*node_id+2;

	/*printf("node_id:%d node_left:%d node_right:%d 一様性が壊れたので、%d と %dに以下の情報を伝達\n",node_id,node_left,node_right,left_child,right_child);
	for(int i = 0; i <= LEN; i++){

		printf("位置%d: %d\n",i,table[node_id][i]);
	}*/

	if(have_info[node_id]){ //子に伝えていない写像情報を持っている場合

		for(int i = 0; i <= LEN; i++){

			table[left_child][i] = table[node_id][table[left_child][i]];
			table[right_child][i] = table[node_id][table[right_child][i]];
		}
		need_calc[left_child] = true;
		need_calc[right_child] = true;
		have_info[node_id] = false;
	}

	int left = query(search_left,search_right,left_child,node_left,(node_left+node_right)/2);
	int right =  query(search_left,search_right,right_child,(node_left+node_right)/2+1,node_right);

	//集計
	//printf("\n");
	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num[left_child][i]+num[right_child][i];
		//printf("num[%d][%d]:%d\n",node_id,i,num[node_id][i]);
	}

	//遷移表初期化
	for(int i = 0; i <= LEN; i++){

		table[node_id][i] = i;
	}

	return left+right;
}

int main(){

	scanf("%s",S);

	for(LEN = 0; S[LEN] != '\0'; LEN++);

	int index,head,max_match_len;

	//len文字一致している状態から、次に文字chが来た時、何文字一致した状態に写るかを計算
	for(int len = 0; len <= LEN; len++){
		for(index = 0; index < len; index++){

			work[index] = S[index];
		}
		for(int ch = 0; ch < 26; ch++){

			work[index] = 'a'+ch;

			if(len == LEN){

				head = 1;
			}else{

				head = 0;
			}

			max_match_len = 0;

			for(int i = head; i <= index; i++){

				bool FLG = true;
				for(int k = i; k <= index; k++){
					if(work[k] != S[k-i]){

						FLG = false;
						break;
					}
				}
				if(FLG){
					max_match_len = index-i+1;
					break;
				}
			}
			next_loc[len][ch] = max_match_len;
			//printf("next_loc[%d][%d]:%d\n",len,ch,next_loc[len][ch]);
		}
	}

	int first_N,num_query;
	scanf("%d %d",&first_N,&num_query);

	init(first_N);

	for(int i = 0; i <= 2*N-2; i++){
		need_calc[i] = false;
		have_info[i] = false;
		for(int k = 0; k <= LEN; k++){
			num[i][k] = 0; //ノードiのカバー範囲において、Sとk文字一致しているノードがいくつあるか
			table[i][k] = k; //最初kにあったマッチ長が、現在どのマッチ位置に遷移しているか
		}
	}

	for(int i = 0; i < first_N; i++){

		update_first(i);
	}

	int command,left,right;

	for(int i = 0; i < num_query; i++){
		scanf("%d",&command);

		if(command == 2){

			scanf("%d %d",&left,&right);
			left--;
			right--;

			//printf("集計 %d-%d\n",left,right);
			printf("%d\n",query(left,right,0,0,N-1));

		}else{
			scanf("%d %d %s",&left,&right,work);
			left--;
			right--;

			for(int k = 0; k <= LEN; k++){

				shift[k] = k;
			}
			for(int a = 0; work[a] != '\0'; a++){
				for(int k = 0; k <= LEN; k++){

					shift[k] = next_loc[shift[k]][work[a]-'a'];
				}
			}

			/*for(int k = 0; k <= LEN; k++){

				printf("shift[%d]:%d\n",k,shift[k]);
			}*/

			//continue;

			update(left,right,0,0,N-1);
		}
	}
	return 0;
}
accuracy: 0.7777777777777778
time_ms: 210
memory_kb: 54928
final_rank: 15

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 500005

int N = 1;
int LEN;
int num[SIZE][25],table[SIZE][25];
int shift[25],num_work[25];
int next_loc[25][26];
bool need_calc[SIZE],have_info[SIZE];
char S[25],work[25];


void init(int first_N){
	while(N < first_N)N *= 2;
}

void update_first(int loc){

	loc += N-1;

	num[loc][0] = 1;

	if(N == 1)return;

	int parent = (loc-1)/2;

	while(true){
		num[parent][0] = num[2*parent+1][0]+num[2*parent+2][0];

		if(parent == 0)break;
		else{
			parent = (parent-1)/2;
		}
	}
}

void calc(int node_id){

	//printf("calc:%d\n",node_id);

	for(int i = 0; i <= LEN; i++){

		num_work[i] = 0;
	}
	for(int i = 0; i <= LEN; i++){

		num_work[table[node_id][i]] += num[node_id][i];
	}
	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num_work[i];
		//printf("num[%d][%d]:%d\n",node_id,i,num[node_id][i]);
	}
}

void update(int search_left,int search_right,int node_id,int node_left,int node_right){

	if(need_calc[node_id]){

		calc(node_id);
		have_info[node_id] = true;
		need_calc[node_id] = false;
	}

	if(search_right < node_left || search_left > node_right)return;

	if(search_left <= node_left && search_right >= node_right){

		//printf("node_id:%d 部分区間内\n",node_id);

		for(int i = 0; i <= LEN; i++){

			num_work[i] = 0;
		}

		for(int i = 0; i <= LEN; i++){

			int next = shift[table[node_id][i]];

			num_work[next] += num[node_id][i];
			table[node_id][i] = next; //回答代行しているかも知れないので、写像表を持っておく
		}
		for(int i = 0; i <= LEN; i++){

			num[node_id][i] = num_work[i];
		}

		have_info[node_id] = true;

		/*printf("遷移表\n");
		for(int i = 0; i <= LEN; i++){

			printf("位置%d %d\n",i,table[node_id][i]);
		}
		printf("個数\n");
		for(int i = 0; i <= LEN; i++){

			printf("位置%d 個数:%d\n",i,num[node_id][i]);
		}*/

		return;
	}


	int left_child = 2*node_id+1;
	int right_child = 2*node_id+2;

	/*printf("node_id:%d node_left:%d node_right:%d 一様性が壊れたので、%d と %dに以下の情報を伝達\n",node_id,node_left,node_right,left_child,right_child);
	for(int i = 0; i <= LEN; i++){

		printf("位置%d: %d\n",i,table[node_id][i]);
	}*/

	if(have_info[node_id]){ //子に伝えていない写像情報を持っている場合

		if(have_info[left_child]){

			update(search_left,search_right,left_child,node_left,(node_left+node_right)/2);
			have_info[left_child] = false;
		}
		if(have_info[right_child]){

			update(search_left,search_right,right_child,(node_left+node_right)/2+1,node_right);
			have_info[right_child] = false;
		}

		for(int i = 0; i <= LEN; i++){

			table[left_child][i] = table[node_id][table[left_child][i]];
			table[right_child][i] = table[node_id][table[right_child][i]];
		}
		need_calc[left_child] = true;
		need_calc[right_child] = true;
		have_info[node_id] = false;
	}

	update(search_left,search_right,left_child,node_left,(node_left+node_right)/2);
	update(search_left,search_right,right_child,(node_left+node_right)/2+1,node_right);

	//集計
	//printf("\n");
	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num[left_child][i]+num[right_child][i];
		//printf("num[%d][%d]:%d\n",node_id,i,num[node_id][i]);
	}

	//遷移表初期化
	for(int i = 0; i <= LEN; i++){

		table[node_id][i] = i;
	}
}

int query(int search_left,int search_right,int node_id,int node_left,int node_right){

	if(need_calc[node_id]){ //遷移表が更新された場合

		calc(node_id);
		have_info[node_id] = true;
		need_calc[node_id] = false;
	}

	if(search_right < node_left || search_left > node_right)return 0;

	if(search_left <= node_left && search_right >= node_right){

		//printf("node_id:%d 部分区間内\n",node_id);
		return num[node_id][LEN];
	}

	//旧情報伝達
	int left_child = 2*node_id+1;
	int right_child = 2*node_id+2;

	/*printf("node_id:%d node_left:%d node_right:%d 一様性が壊れたので、%d と %dに以下の情報を伝達\n",node_id,node_left,node_right,left_child,right_child);
	for(int i = 0; i <= LEN; i++){

		printf("位置%d: %d\n",i,table[node_id][i]);
	}*/

	if(have_info[node_id]){ //子に伝えていない写像情報を持っている場合

		if(have_info[left_child]){

			query(search_left,search_right,left_child,node_left,(node_left+node_right)/2);
			have_info[left_child] = false;
		}
		if(have_info[right_child]){

			query(search_left,search_right,right_child,(node_left+node_right)/2+1,node_right);
			have_info[right_child] = false;
		}

		for(int i = 0; i <= LEN; i++){

			table[left_child][i] = table[node_id][table[left_child][i]];
			table[right_child][i] = table[node_id][table[right_child][i]];
		}
		need_calc[left_child] = true;
		need_calc[right_child] = true;
		have_info[node_id] = false;
	}

	int left = query(search_left,search_right,left_child,node_left,(node_left+node_right)/2);
	int right =  query(search_left,search_right,right_child,(node_left+node_right)/2+1,node_right);

	//集計
	//printf("\n");
	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num[left_child][i]+num[right_child][i];
		//printf("num[%d][%d]:%d\n",node_id,i,num[node_id][i]);
	}

	//遷移表初期化
	for(int i = 0; i <= LEN; i++){

		table[node_id][i] = i;
	}

	return left+right;
}

int main(){

	scanf("%s",S);

	for(LEN = 0; S[LEN] != '\0'; LEN++);

	int index,head,max_match_len;

	//len文字一致している状態から、次に文字chが来た時、何文字一致した状態に写るかを計算
	for(int len = 0; len <= LEN; len++){
		for(index = 0; index < len; index++){

			work[index] = S[index];
		}
		for(int ch = 0; ch < 26; ch++){

			work[index] = 'a'+ch;

			if(len == LEN){

				head = 1;
			}else{

				head = 0;
			}

			max_match_len = 0;

			for(int i = head; i <= index; i++){

				bool FLG = true;
				for(int k = i; k <= index; k++){
					if(work[k] != S[k-i]){

						FLG = false;
						break;
					}
				}
				if(FLG){
					max_match_len = index-i+1;
					break;
				}
			}
			next_loc[len][ch] = max_match_len;
			//printf("next_loc[%d][%d]:%d\n",len,ch,next_loc[len][ch]);
		}
	}

	int first_N,num_query;
	scanf("%d %d",&first_N,&num_query);

	init(first_N);

	for(int i = 0; i <= 2*N-2; i++){
		need_calc[i] = false;
		have_info[i] = false;
		for(int k = 0; k <= LEN; k++){
			num[i][k] = 0; //ノードiのカバー範囲において、Sとk文字一致しているノードがいくつあるか
			table[i][k] = k; //最初kにあったマッチ長が、現在どのマッチ位置に遷移しているか
		}
	}

	for(int i = 0; i < first_N; i++){

		update_first(i);
	}

	int command,left,right;

	for(int i = 0; i < num_query; i++){
		scanf("%d",&command);

		if(command == 2){

			scanf("%d %d",&left,&right);
			left--;
			right--;

			//printf("集計 %d-%d\n",left,right);
			printf("%d\n",query(left,right,0,0,N-1));

		}else{
			scanf("%d %d %s",&left,&right,work);
			left--;
			right--;

			for(int k = 0; k <= LEN; k++){

				shift[k] = k;
			}
			for(int a = 0; work[a] != '\0'; a++){
				for(int k = 0; k <= LEN; k++){

					shift[k] = next_loc[shift[k]][work[a]-'a'];
				}
			}

			/*for(int k = 0; k <= LEN; k++){

				printf("shift[%d]:%d\n",k,shift[k]);
			}*/

			//continue;

			update(left,right,0,0,N-1);
		}
	}
	return 0;
}
accuracy: 0.7777777777777778
time_ms: 460
memory_kb: 54932
final_rank: 18

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 500005

int N = 1;
int LEN;
int num[SIZE][25],table[SIZE][25];
int shift[25],num_work[25];
int next_loc[25][26];
bool need_calc[SIZE],have_info[SIZE];
char S[25],work[25];


void init(int first_N){
	while(N < first_N)N *= 2;
}

void update_first(int loc){

	loc += N-1;

	num[loc][0] = 1;

	if(N == 1)return;

	int parent = (loc-1)/2;

	while(true){
		num[parent][0] = num[2*parent+1][0]+num[2*parent+2][0];

		if(parent == 0)break;
		else{
			parent = (parent-1)/2;
		}
	}
}

void calc(int node_id){

	//printf("calc:%d\n",node_id);

	for(int i = 0; i <= LEN; i++){

		num_work[i] = 0;
	}
	for(int i = 0; i <= LEN; i++){

		num_work[table[node_id][i]] += num[node_id][i];
	}
	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num_work[i];
		//printf("num[%d][%d]:%d\n",node_id,i,num[node_id][i]);
	}
}

void update(int search_left,int search_right,int node_id,int node_left,int node_right){

	if(need_calc[node_id]){

		calc(node_id);
		have_info[node_id] = true;
		need_calc[node_id] = false;
	}

	if(search_right < node_left || search_left > node_right)return;

	if(search_left <= node_left && search_right >= node_right){

		//printf("node_id:%d 部分区間内\n",node_id);

		for(int i = 0; i <= LEN; i++){

			num_work[i] = 0;
		}

		for(int i = 0; i <= LEN; i++){

			int next = shift[table[node_id][i]];

			num_work[next] += num[node_id][i];
			table[node_id][i] = next; //回答代行しているかも知れないので、写像表を持っておく
		}
		for(int i = 0; i <= LEN; i++){

			num[node_id][i] = num_work[i];
		}

		have_info[node_id] = true;

		/*printf("遷移表\n");
		for(int i = 0; i <= LEN; i++){

			printf("位置%d %d\n",i,table[node_id][i]);
		}
		printf("個数\n");
		for(int i = 0; i <= LEN; i++){

			printf("位置%d 個数:%d\n",i,num[node_id][i]);
		}*/

		return;
	}


	int left_child = 2*node_id+1;
	int right_child = 2*node_id+2;

	/*printf("node_id:%d node_left:%d node_right:%d 一様性が壊れたので、%d と %dに以下の情報を伝達\n",node_id,node_left,node_right,left_child,right_child);
	for(int i = 0; i <= LEN; i++){

		printf("位置%d: %d\n",i,table[node_id][i]);
	}*/

	if(have_info[node_id]){ //子に伝えていない写像情報を持っている場合

			for(int i = 0; i <= LEN; i++){
				int pre = table[left_child][i];
				table[left_child][i] = table[node_id][pre];
				pre = table[right_child][i];
				table[right_child][i] = table[node_id][pre];
			}
			need_calc[left_child] = true;
			need_calc[right_child] = true;
			have_info[node_id] = false;
		}

	update(search_left,search_right,left_child,node_left,(node_left+node_right)/2);
	update(search_left,search_right,right_child,(node_left+node_right)/2+1,node_right);

	//集計
	//printf("\n");
	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num[left_child][i]+num[right_child][i];
		//printf("num[%d][%d]:%d\n",node_id,i,num[node_id][i]);
	}

	//遷移表初期化
	for(int i = 0; i <= LEN; i++){

		table[node_id][i] = i;
	}
}

int query(int search_left,int search_right,int node_id,int node_left,int node_right){

	if(need_calc[node_id]){ //遷移表が更新された場合

		calc(node_id);
		have_info[node_id] = true;
		need_calc[node_id] = false;
	}

	if(search_right < node_left || search_left > node_right)return 0;

	if(search_left <= node_left && search_right >= node_right){

		//printf("node_id:%d 部分区間内\n",node_id);
		//遷移表が更新されたとは限らないので、have_infoは操作しない
		return num[node_id][LEN];
	}

	//旧情報伝達
	int left_child = 2*node_id+1;
	int right_child = 2*node_id+2;

	/*printf("node_id:%d node_left:%d node_right:%d 一様性が壊れたので、%d と %dに以下の情報を伝達\n",node_id,node_left,node_right,left_child,right_child);
	for(int i = 0; i <= LEN; i++){

		printf("位置%d: %d\n",i,table[node_id][i]);
	}*/

	if(have_info[node_id]){ //子に伝えていない写像情報を持っている場合

		for(int i = 0; i <= LEN; i++){
			int pre = table[left_child][i];
			table[left_child][i] = table[node_id][pre];
			pre = table[right_child][i];
			table[right_child][i] = table[node_id][pre];
		}
		need_calc[left_child] = true;
		need_calc[right_child] = true;
		have_info[node_id] = false;
	}

	int left = query(search_left,search_right,left_child,node_left,(node_left+node_right)/2);
	int right =  query(search_left,search_right,right_child,(node_left+node_right)/2+1,node_right);

	//集計
	//printf("\n");
	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num[left_child][i]+num[right_child][i];
		//printf("num[%d][%d]:%d\n",node_id,i,num[node_id][i]);
	}

	//遷移表初期化
	for(int i = 0; i <= LEN; i++){

		table[node_id][i] = i;
	}

	return left+right;
}

int main(){

	scanf("%s",S);

	for(LEN = 0; S[LEN] != '\0'; LEN++);

	int index,head,max_match_len;

	//len文字一致している状態から、次に文字chが来た時、何文字一致した状態に写るかを計算
	for(int len = 0; len <= LEN; len++){
		for(index = 0; index < len; index++){

			work[index] = S[index];
		}
		for(int ch = 0; ch < 26; ch++){

			work[index] = 'a'+ch;

			if(len == LEN){

				head = 1;
			}else{

				head = 0;
			}

			max_match_len = 0;

			for(int i = head; i <= index; i++){

				bool FLG = true;
				for(int k = i; k <= index; k++){
					if(work[k] != S[k-i]){

						FLG = false;
						break;
					}
				}
				if(FLG){
					max_match_len = index-i+1;
					break;
				}
			}
			next_loc[len][ch] = max_match_len;
			//printf("next_loc[%d][%d]:%d\n",len,ch,next_loc[len][ch]);
		}
	}

	int first_N,num_query;
	scanf("%d %d",&first_N,&num_query);

	init(first_N);

	for(int i = 0; i <= 2*N-2; i++){
		need_calc[i] = false;
		have_info[i] = false;
		for(int k = 0; k <= LEN; k++){
			num[i][k] = 0; //ノードiのカバー範囲において、Sとk文字一致しているノードがいくつあるか
			table[i][k] = k; //最初kにあったマッチ長が、現在どのマッチ位置に遷移しているか
		}
	}

	for(int i = 0; i < first_N; i++){

		update_first(i);
	}

	int command,left,right;

	for(int i = 0; i < num_query; i++){
		scanf("%d",&command);

		if(command == 2){

			scanf("%d %d",&left,&right);
			left--;
			right--;

			//printf("集計 %d-%d\n",left,right);
			printf("%d\n",query(left,right,0,0,N-1));

		}else{
			scanf("%d %d %s",&left,&right,work);
			left--;
			right--;

			for(int k = 0; k <= LEN; k++){

				shift[k] = k;
			}
			for(int a = 0; work[a] != '\0'; a++){
				for(int k = 0; k <= LEN; k++){

					shift[k] = next_loc[shift[k]][work[a]-'a'];
				}
			}

			/*for(int k = 0; k <= LEN; k++){

				printf("shift[%d]:%d\n",k,shift[k]);
			}*/

			//continue;

			update(left,right,0,0,N-1);
		}
	}
	return 0;
}
accuracy: 0.7777777777777778
time_ms: 210
memory_kb: 54876
final_rank: 14

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 500005

int N = 1;
int LEN;
int num[SIZE][25],table[SIZE][25];
int shift[25],num_work[25];
int next_loc[25][26];
bool need_calc[SIZE],have_info[SIZE];
char S[25],work[25];


void init(int first_N){
	while(N < first_N)N *= 2;
}

void update_first(int loc){

	loc += N-1;

	num[loc][0] = 1;

	if(N == 1)return;

	int parent = (loc-1)/2;

	while(true){
		num[parent][0] = num[2*parent+1][0]+num[2*parent+2][0];

		if(parent == 0)break;
		else{
			parent = (parent-1)/2;
		}
	}
}

void calc(int node_id){

	//printf("calc:%d\n",node_id);

	for(int i = 0; i <= LEN; i++){

		num_work[i] = 0;
	}
	for(int i = 0; i <= LEN; i++){

		num_work[table[node_id][i]] += num[node_id][i];
	}
	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num_work[i];
		//printf("num[%d][%d]:%d\n",node_id,i,num[node_id][i]);
	}
}

void update(int search_left,int search_right,int node_id,int node_left,int node_right){

	if(need_calc[node_id]){

		calc(node_id);
		have_info[node_id] = true;
		need_calc[node_id] = false;
	}

	if(search_right < node_left || search_left > node_right)return;

	if(search_left <= node_left && search_right >= node_right){

		//printf("node_id:%d 部分区間内\n",node_id);

		for(int i = 0; i <= LEN; i++){

			num_work[i] = 0;
		}

		for(int i = 0; i <= LEN; i++){

			int next = shift[table[node_id][i]];

			num_work[next] += num[node_id][i];
			table[node_id][i] = next; //回答代行しているかも知れないので、写像表を持っておく
		}
		for(int i = 0; i <= LEN; i++){

			num[node_id][i] = num_work[i];
		}

		have_info[node_id] = false;

		if(node_left < node_right){

			int left_child = 2*node_id+1;
			int right_child = 2*node_id+2;

			for(int i = 0; i <= LEN; i++){

				table[left_child][i] = table[node_id][table[left_child][i]];
				table[right_child][i] = table[node_id][table[right_child][i]];
			}
			need_calc[left_child] = true;
			need_calc[right_child] = true;
		}

		//遷移表初期化
		for(int i = 0; i <= LEN; i++){

			table[node_id][i] = i;
		}

		/*printf("遷移表\n");
		for(int i = 0; i <= LEN; i++){

			printf("位置%d %d\n",i,table[node_id][i]);
		}
		printf("個数\n");
		for(int i = 0; i <= LEN; i++){

			printf("位置%d 個数:%d\n",i,num[node_id][i]);
		}*/

		return;
	}


	int left_child = 2*node_id+1;
	int right_child = 2*node_id+2;

	/*printf("node_id:%d node_left:%d node_right:%d 一様性が壊れたので、%d と %dに以下の情報を伝達\n",node_id,node_left,node_right,left_child,right_child);
	for(int i = 0; i <= LEN; i++){

		printf("位置%d: %d\n",i,table[node_id][i]);
	}*/

	if(have_info[node_id]){ //子に伝えていない写像情報を持っている場合

		for(int i = 0; i <= LEN; i++){

			table[left_child][i] = table[node_id][table[left_child][i]];
			table[right_child][i] = table[node_id][table[right_child][i]];
		}
		need_calc[left_child] = true;
		need_calc[right_child] = true;
		have_info[node_id] = false;
	}

	update(search_left,search_right,left_child,node_left,(node_left+node_right)/2);
	update(search_left,search_right,right_child,(node_left+node_right)/2+1,node_right);

	//集計
	//printf("\n");
	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num[left_child][i]+num[right_child][i];
		//printf("num[%d][%d]:%d\n",node_id,i,num[node_id][i]);
	}

	//遷移表初期化
	for(int i = 0; i <= LEN; i++){

		table[node_id][i] = i;
	}
}

int query(int search_left,int search_right,int node_id,int node_left,int node_right){

	if(need_calc[node_id]){ //遷移表が更新された場合

		calc(node_id);
		have_info[node_id] = true;
		need_calc[node_id] = false;
	}

	if(search_right < node_left || search_left > node_right)return 0;

	if(search_left <= node_left && search_right >= node_right){

		//printf("node_id:%d 部分区間内\n",node_id);
		return num[node_id][LEN];
	}

	//旧情報伝達
	int left_child = 2*node_id+1;
	int right_child = 2*node_id+2;

	/*printf("node_id:%d node_left:%d node_right:%d 一様性が壊れたので、%d と %dに以下の情報を伝達\n",node_id,node_left,node_right,left_child,right_child);
	for(int i = 0; i <= LEN; i++){

		printf("位置%d: %d\n",i,table[node_id][i]);
	}*/

	if(have_info[node_id]){ //子に伝えていない写像情報を持っている場合

		for(int i = 0; i <= LEN; i++){

			table[left_child][i] = table[node_id][table[left_child][i]];
			table[right_child][i] = table[node_id][table[right_child][i]];
		}
		need_calc[left_child] = true;
		need_calc[right_child] = true;
		have_info[node_id] = false;
	}

	int left = query(search_left,search_right,left_child,node_left,(node_left+node_right)/2);
	int right =  query(search_left,search_right,right_child,(node_left+node_right)/2+1,node_right);

	//集計
	//printf("\n");
	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num[left_child][i]+num[right_child][i];
		//printf("num[%d][%d]:%d\n",node_id,i,num[node_id][i]);
	}

	//遷移表初期化
	for(int i = 0; i <= LEN; i++){

		table[node_id][i] = i;
	}

	return left+right;
}

int main(){

	scanf("%s",S);

	for(LEN = 0; S[LEN] != '\0'; LEN++);

	int index,head,max_match_len;

	//len文字一致している状態から、次に文字chが来た時、何文字一致した状態に写るかを計算
	for(int len = 0; len <= LEN; len++){
		for(index = 0; index < len; index++){

			work[index] = S[index];
		}
		for(int ch = 0; ch < 26; ch++){

			work[index] = 'a'+ch;

			if(len == LEN){

				head = 1;
			}else{

				head = 0;
			}

			max_match_len = 0;

			for(int i = head; i <= index; i++){

				bool FLG = true;
				for(int k = i; k <= index; k++){
					if(work[k] != S[k-i]){

						FLG = false;
						break;
					}
				}
				if(FLG){
					max_match_len = index-i+1;
					break;
				}
			}
			next_loc[len][ch] = max_match_len;
			//printf("next_loc[%d][%d]:%d\n",len,ch,next_loc[len][ch]);
		}
	}

	int first_N,num_query;
	scanf("%d %d",&first_N,&num_query);

	init(first_N);

	for(int i = 0; i <= 2*N-2; i++){
		need_calc[i] = false;
		have_info[i] = false;
		for(int k = 0; k <= LEN; k++){
			num[i][k] = 0; //ノードiのカバー範囲において、Sとk文字一致しているノードがいくつあるか
			table[i][k] = k; //最初kにあったマッチ長が、現在どのマッチ位置に遷移しているか
		}
	}

	for(int i = 0; i < first_N; i++){

		update_first(i);
	}

	int command,left,right;

	for(int i = 0; i < num_query; i++){
		scanf("%d",&command);

		if(command == 2){

			scanf("%d %d",&left,&right);
			left--;
			right--;

			//printf("集計 %d-%d\n",left,right);
			printf("%d\n",query(left,right,0,0,N-1));

		}else{
			scanf("%d %d %s",&left,&right,work);
			left--;
			right--;

			for(int k = 0; k <= LEN; k++){

				shift[k] = k;
			}
			for(int a = 0; work[a] != '\0'; a++){
				for(int k = 0; k <= LEN; k++){

					shift[k] = next_loc[shift[k]][work[a]-'a'];
				}
			}

			/*for(int k = 0; k <= LEN; k++){

				printf("shift[%d]:%d\n",k,shift[k]);
			}*/

			//continue;

			update(left,right,0,0,N-1);
		}
	}
	return 0;
}
accuracy: 0.7777777777777778
time_ms: 220
memory_kb: 54876
final_rank: 16

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 500005

int N = 1;
int LEN;
int num[SIZE][25],table[SIZE][25];
int shift[25],num_work[25];
int next_loc[25][26];
bool need_calc[SIZE],have_info[SIZE];
char S[25],work[25];


void init(int first_N){
	while(N < first_N)N *= 2;
}

void update_first(int loc){

	loc += N-1;

	num[loc][0] = 1;

	if(N == 1)return;

	int parent = (loc-1)/2;

	while(true){
		num[parent][0] = num[2*parent+1][0]+num[2*parent+2][0];

		if(parent == 0)break;
		else{
			parent = (parent-1)/2;
		}
	}
}

void calc(int node_id){

	//printf("calc:%d\n",node_id);

	for(int i = 0; i <= LEN; i++){

		num_work[i] = 0;
	}
	for(int i = 0; i <= LEN; i++){

		num_work[table[node_id][i]] += num[node_id][i];
	}
	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num_work[i];
		//printf("num[%d][%d]:%d\n",node_id,i,num[node_id][i]);
	}
}

void update(int search_left,int search_right,int node_id,int node_left,int node_right){

	if(need_calc[node_id]){

		calc(node_id);
		have_info[node_id] = true;
		need_calc[node_id] = false;
	}

	if(search_right < node_left || search_left > node_right)return;

	if(search_left <= node_left && search_right >= node_right){

		//printf("node_id:%d 部分区間内\n",node_id);

		for(int i = 0; i <= LEN; i++){

			num_work[i] = 0;
		}

		for(int i = 0; i <= LEN; i++){

			int next = shift[table[node_id][i]];

			num_work[next] += num[node_id][i];
			table[node_id][i] = next; //回答代行しているかも知れないので、写像表を持っておく
		}
		for(int i = 0; i <= LEN; i++){

			num[node_id][i] = num_work[i];
		}

		have_info[node_id] = true;

		/*printf("遷移表\n");
		for(int i = 0; i <= LEN; i++){

			printf("位置%d %d\n",i,table[node_id][i]);
		}
		printf("個数\n");
		for(int i = 0; i <= LEN; i++){

			printf("位置%d 個数:%d\n",i,num[node_id][i]);
		}*/

		return;
	}


	int left_child = 2*node_id+1;
	int right_child = 2*node_id+2;

	/*printf("node_id:%d node_left:%d node_right:%d 一様性が壊れたので、%d と %dに以下の情報を伝達\n",node_id,node_left,node_right,left_child,right_child);
	for(int i = 0; i <= LEN; i++){

		printf("位置%d: %d\n",i,table[node_id][i]);
	}*/

	if(have_info[node_id] == true && node_left < node_right){ //子に伝えていない写像情報を持っている場合

		for(int i = 0; i <= LEN; i++){

			table[left_child][i] = table[node_id][table[left_child][i]];
			table[right_child][i] = table[node_id][table[right_child][i]];
		}
		need_calc[left_child] = true;
		need_calc[right_child] = true;
		have_info[node_id] = false;
	}

	update(search_left,search_right,left_child,node_left,(node_left+node_right)/2);
	update(search_left,search_right,right_child,(node_left+node_right)/2+1,node_right);

	//集計
	//printf("\n");
	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num[left_child][i]+num[right_child][i];
		//printf("num[%d][%d]:%d\n",node_id,i,num[node_id][i]);
	}

	//遷移表初期化
	for(int i = 0; i <= LEN; i++){

		table[node_id][i] = i;
	}
}

int query(int search_left,int search_right,int node_id,int node_left,int node_right){

	if(need_calc[node_id]){ //遷移表が更新された場合

		calc(node_id);
		have_info[node_id] = true;
		need_calc[node_id] = false;
	}

	if(search_right < node_left || search_left > node_right)return 0;

	if(search_left <= node_left && search_right >= node_right){

		//printf("node_id:%d 部分区間内\n",node_id);
		return num[node_id][LEN];
	}

	//旧情報伝達
	int left_child = 2*node_id+1;
	int right_child = 2*node_id+2;

	/*printf("node_id:%d node_left:%d node_right:%d 一様性が壊れたので、%d と %dに以下の情報を伝達\n",node_id,node_left,node_right,left_child,right_child);
	for(int i = 0; i <= LEN; i++){

		printf("位置%d: %d\n",i,table[node_id][i]);
	}*/

	if(have_info[node_id] == true && node_left < node_right){ //子に伝えていない写像情報を持っている場合

		for(int i = 0; i <= LEN; i++){

			table[left_child][i] = table[node_id][table[left_child][i]];
			table[right_child][i] = table[node_id][table[right_child][i]];
		}
		need_calc[left_child] = true;
		need_calc[right_child] = true;
		have_info[node_id] = false;
	}

	int left = query(search_left,search_right,left_child,node_left,(node_left+node_right)/2);
	int right =  query(search_left,search_right,right_child,(node_left+node_right)/2+1,node_right);

	//集計
	//printf("\n");
	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num[left_child][i]+num[right_child][i];
		//printf("num[%d][%d]:%d\n",node_id,i,num[node_id][i]);
	}

	//遷移表初期化
	for(int i = 0; i <= LEN; i++){

		table[node_id][i] = i;
	}

	return left+right;
}

int main(){

	scanf("%s",S);

	for(LEN = 0; S[LEN] != '\0'; LEN++);

	int index,head,max_match_len;

	//len文字一致している状態から、次に文字chが来た時、何文字一致した状態に写るかを計算
	for(int len = 0; len <= LEN; len++){
		for(index = 0; index < len; index++){

			work[index] = S[index];
		}
		for(int ch = 0; ch < 26; ch++){

			work[index] = 'a'+ch;

			if(len == LEN){

				head = 1;
			}else{

				head = 0;
			}

			max_match_len = 0;

			for(int i = head; i <= index; i++){

				bool FLG = true;
				for(int k = i; k <= index; k++){
					if(work[k] != S[k-i]){

						FLG = false;
						break;
					}
				}
				if(FLG){
					max_match_len = index-i+1;
					break;
				}
			}
			next_loc[len][ch] = max_match_len;
			//printf("next_loc[%d][%d]:%d\n",len,ch,next_loc[len][ch]);
		}
	}

	int first_N,num_query;
	scanf("%d %d",&first_N,&num_query);

	init(first_N);

	for(int i = 0; i <= 2*N-2; i++){
		need_calc[i] = false;
		have_info[i] = false;
		for(int k = 0; k <= LEN; k++){
			num[i][k] = 0; //ノードiのカバー範囲において、Sとk文字一致しているノードがいくつあるか
			table[i][k] = k; //最初kにあったマッチ長が、現在どのマッチ位置に遷移しているか
		}
	}

	for(int i = 0; i < first_N; i++){

		update_first(i);
	}

	int command,left,right;

	for(int i = 0; i < num_query; i++){
		scanf("%d",&command);

		if(command == 2){

			scanf("%d %d",&left,&right);
			left--;
			right--;

			//printf("集計 %d-%d\n",left,right);
			printf("%d\n",query(left,right,0,0,N-1));

		}else{
			scanf("%d %d %s",&left,&right,work);
			left--;
			right--;

			for(int k = 0; k <= LEN; k++){

				shift[k] = k;
			}
			for(int a = 0; work[a] != '\0'; a++){
				for(int k = 0; k <= LEN; k++){

					shift[k] = next_loc[shift[k]][work[a]-'a'];
				}
			}

			/*for(int k = 0; k <= LEN; k++){

				printf("shift[%d]:%d\n",k,shift[k]);
			}*/

			//continue;

			update(left,right,0,0,N-1);
		}
	}
	return 0;
}
accuracy: 0.7777777777777778
time_ms: 200
memory_kb: 54936
final_rank: 13

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 500005

int N = 1;
int LEN;
int num[SIZE][25],table[SIZE][25];
int shift[25],num_work[25];
int next_loc[25][26];
bool need_calc[SIZE],have_info[SIZE];
char S[25],work[25];


void init(int first_N){
	while(N < first_N)N *= 2;
}

void update_first(int loc){

	loc += N-1;

	num[loc][0] = 1;

	if(N == 1)return;

	int parent = (loc-1)/2;

	while(true){
		num[parent][0] = num[2*parent+1][0]+num[2*parent+2][0];

		if(parent == 0)break;
		else{
			parent = (parent-1)/2;
		}
	}
}

void calc(int node_id){

	//printf("calc:%d\n",node_id);

	for(int i = 0; i <= LEN; i++){

		num_work[i] = 0;
	}
	for(int i = 0; i <= LEN; i++){

		num_work[table[node_id][i]] += num[node_id][i];
	}
	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num_work[i];
		//printf("num[%d][%d]:%d\n",node_id,i,num[node_id][i]);
	}
}

void update(int search_left,int search_right,int node_id,int node_left,int node_right){

	if(need_calc[node_id]){

		calc(node_id);
		have_info[node_id] = true;
		need_calc[node_id] = false;
	}

	if(search_right < node_left || search_left > node_right)return;

	if(search_left <= node_left && search_right >= node_right){

		//printf("node_id:%d 部分区間内\n",node_id);

		for(int i = 0; i <= LEN; i++){

			num_work[i] = 0;
		}

		for(int i = 0; i <= LEN; i++){

			int next = shift[table[node_id][i]];

			num_work[next] += num[node_id][i];
			table[node_id][i] = next; //回答代行しているかも知れないので、写像表を持っておく
		}
		for(int i = 0; i <= LEN; i++){

			num[node_id][i] = num_work[i];
		}

		have_info[node_id] = true;

		/*printf("遷移表\n");
		for(int i = 0; i <= LEN; i++){

			printf("位置%d %d\n",i,table[node_id][i]);
		}
		printf("個数\n");
		for(int i = 0; i <= LEN; i++){

			printf("位置%d 個数:%d\n",i,num[node_id][i]);
		}*/

		return;
	}


	int left_child = 2*node_id+1;
	int right_child = 2*node_id+2;

	/*printf("node_id:%d node_left:%d node_right:%d 一様性が壊れたので、%d と %dに以下の情報を伝達\n",node_id,node_left,node_right,left_child,right_child);
	for(int i = 0; i <= LEN; i++){

		printf("位置%d: %d\n",i,table[node_id][i]);
	}*/

	if(have_info[node_id]){ //子に伝えていない写像情報を持っている場合

		for(int i = 0; i <= LEN; i++){

			table[left_child][i] = table[node_id][table[left_child][i]];
			table[right_child][i] = table[node_id][table[right_child][i]];
		}
		need_calc[left_child] = true;
		need_calc[right_child] = true;
		have_info[node_id] = false;
	}

	update(search_left,search_right,left_child,node_left,(node_left+node_right)/2);
	update(search_left,search_right,right_child,(node_left+node_right)/2+1,node_right);

	//集計
	//printf("\n");
	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num[left_child][i]+num[right_child][i];
		//printf("num[%d][%d]:%d\n",node_id,i,num[node_id][i]);
	}

	//遷移表初期化
	for(int i = 0; i <= LEN; i++){

		table[node_id][i] = i;
	}
}

int query(int search_left,int search_right,int node_id,int node_left,int node_right){

	if(need_calc[node_id]){ //遷移表が更新された場合

		calc(node_id);
		have_info[node_id] = true;
		need_calc[node_id] = false;
	}

	if(search_right < node_left || search_left > node_right)return 0;

	if(search_left <= node_left && search_right >= node_right){

		//printf("node_id:%d 部分区間内\n",node_id);
		//have_info[node_id] = true;
		return num[node_id][LEN];
	}

	//旧情報伝達
	int left_child = 2*node_id+1;
	int right_child = 2*node_id+2;

	/*printf("node_id:%d node_left:%d node_right:%d 一様性が壊れたので、%d と %dに以下の情報を伝達\n",node_id,node_left,node_right,left_child,right_child);
	for(int i = 0; i <= LEN; i++){

		printf("位置%d: %d\n",i,table[node_id][i]);
	}*/

	if(have_info[node_id]){ //子に伝えていない写像情報を持っている場合

		for(int i = 0; i <= LEN; i++){

			table[left_child][i] = table[node_id][table[left_child][i]];
			table[right_child][i] = table[node_id][table[right_child][i]];
		}
		need_calc[left_child] = true;
		need_calc[right_child] = true;
		have_info[node_id] = false;
	}

	int left = query(search_left,search_right,left_child,node_left,(node_left+node_right)/2);
	int right =  query(search_left,search_right,right_child,(node_left+node_right)/2+1,node_right);

	//集計
	//printf("\n");
	for(int i = 0; i <= LEN; i++){

		num[node_id][i] = num[left_child][i]+num[right_child][i];
		//printf("num[%d][%d]:%d\n",node_id,i,num[node_id][i]);
	}

	//遷移表初期化
	for(int i = 0; i <= LEN; i++){

		table[node_id][i] = i;
	}

	return left+right;
}

int main(){

	scanf("%s",S);

	for(LEN = 0; S[LEN] != '\0'; LEN++);

	int index,head,max_match_len;

	//len文字一致している状態から、次に文字chが来た時、何文字一致した状態に写るかを計算
	for(int len = 0; len <= LEN; len++){
		for(index = 0; index < len; index++){

			work[index] = S[index];
		}
		for(int ch = 0; ch < 26; ch++){

			work[index] = 'a'+ch;

			if(len == LEN){

				head = 1;
			}else{

				head = 0;
			}

			max_match_len = 0;

			for(int i = head; i <= index; i++){

				bool FLG = true;
				for(int k = i; k <= index; k++){
					if(work[k] != S[k-i]){

						FLG = false;
						break;
					}
				}
				if(FLG){
					max_match_len = index-i+1;
					break;
				}
			}
			next_loc[len][ch] = max_match_len;
			//printf("next_loc[%d][%d]:%d\n",len,ch,next_loc[len][ch]);
		}
	}

	int first_N,num_query;
	scanf("%d %d",&first_N,&num_query);

	init(first_N);

	for(int i = 0; i <= 2*N-2; i++){
		need_calc[i] = false;
		have_info[i] = false;
		for(int k = 0; k <= LEN; k++){
			num[i][k] = 0; //ノードiのカバー範囲において、Sとk文字一致しているノードがいくつあるか
			table[i][k] = k; //最初kにあったマッチ長が、現在どのマッチ位置に遷移しているか
		}
	}

	for(int i = 0; i < first_N; i++){

		update_first(i);
	}

	int command,left,right;

	for(int i = 0; i < num_query; i++){
		scanf("%d",&command);

		if(command == 2){

			scanf("%d %d",&left,&right);
			left--;
			right--;

			//printf("集計 %d-%d\n",left,right);
			printf("%d\n",query(left,right,0,0,N-1));

		}else{
			scanf("%d %d %s",&left,&right,work);
			left--;
			right--;

			for(int k = 0; k <= LEN; k++){

				shift[k] = k;
			}
			for(int a = 0; work[a] != '\0'; a++){
				for(int k = 0; k <= LEN; k++){

					shift[k] = next_loc[shift[k]][work[a]-'a'];
				}
			}

			/*for(int k = 0; k <= LEN; k++){

				printf("shift[%d]:%d\n",k,shift[k]);
			}*/

			//continue;

			update(left,right,0,0,N-1);
		}
	}
	return 0;
}
accuracy: 0.7777777777777778
time_ms: 200
memory_kb: 54912
final_rank: 12

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
template<class T> using vec = vector<T>;
template<class T> using vvec = vector<vec<T>>;

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

	int sz,height;
	vec<Monoid> data;
	vec<OperatorMonoid> lazy;
	const F op;
	const G homo;
	const H comp;
  	const Monoid e;
	const OperatorMonoid Oe;

	LazySegmentTree(int n,const F op,const G homo,const H comp,
					const Monoid &e,const OperatorMonoid Oe)
		: op(op),homo(homo),comp(comp),e(e),Oe(Oe) {
		sz = 1;
		height = 0;
		while(sz<=n) sz <<= 1,height++;
		data.assign(2*sz,e);
		lazy.assign(2*sz,Oe);
	}

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

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

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

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

	inline void recalc(int k) {
		while(k>>=1) data[k] = op(reflect(2*k), 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] = comp(lazy[l],x),++l;
			if(r&1) --r, lazy[r] = comp(lazy[r],x);
		}
		recalc(a);
		recalc(b);
	}

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

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

using arr = array<int,21>;

vector<int> Z_algorithm(string S){
    int M = S.size();
    vector<int> A(M,0);
    A[0] = M;
    int i = 1,j = 0;
    while(i<M){
        while(i+j<M && S[j]==S[i+j]) j++;
        A[i] = j;
        if(j==0){
            i++;
            continue;
        }
        int k = 1;
        while(i+k<M && k+A[k]<j){
            A[i+k] = A[k];
            k++;
        }
        i += k; j -= k;
    }
    return A;
}

int main(){
    cin.tie(0);
    ios::sync_with_stdio(false);
    string S;
    int N,Q;
    cin >> S >> N >> Q;
	int n = S.size();
	auto op = [&](arr L,arr R){
		arr res{};
		for(int i=0;i<=n;i++) res[i] = L[i]+R[i];
		return res;
	};

	auto homo = [&](arr S,arr f){
		arr res{};
		for(int i=0;i<=n;i++) res[f[i]] += S[i];
		return res;
	};

	auto comp = [&](arr f,arr g){
		arr res{};
		for(int i=0;i<=n;i++) res[i] = g[f[i]];
		return res;
	};

	arr id{};
	for(int i=0;i<=20;i++) id[i] = i;
	LazySegmentTree<arr,arr,decltype(op),decltype(homo),decltype(comp)>
	seg(N,op,homo,comp,arr{},id);
	for(int i=0;i<N;i++){
		arr a{};
		a[0] = 1;
		seg.set(i,a);
	}
	seg.build();

	for(int i=0;i<Q;i++){
		int t;
		cin >> t;
		if(t==1){
			int l,r;
			string c;
			cin >> l >> r >> c;
			l--; r--;
			arr f{};
			int m = c.size();
			for(int i=0;i<=n;i++){
				string s = S.substr(0,i)+c;
				vec<int> res = Z_algorithm(S+s);
				for(int j=max(i+m,n);j<n+i+m;j++){
					if(j+res[j]==n+i+m) f[i] = max(f[i],min(res[j],n));
				}
			}
			seg.update(l,r+1,f);
		}else{
			int l,r;
			cin >> l >> r;
			l--; r--;
			cout << seg.query(l,r+1)[n] << "\n";
		}
	}
}
accuracy: 1
time_ms: 1220
memory_kb: 45996
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
template<class T> using vec = vector<T>;
template<class T> using vvec = vector<vec<T>>;

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

	int sz,height;
	vec<Monoid> data;
	vec<OperatorMonoid> lazy;
	const F op;
	const G homo;
	const H comp;
  	const Monoid e;
	const OperatorMonoid Oe;

	LazySegmentTree(int n,const F op,const G homo,const H comp,
					const Monoid &e,const OperatorMonoid Oe)
		: op(op),homo(homo),comp(comp),e(e),Oe(Oe) {
		sz = 1;
		height = 0;
		while(sz<=n) sz <<= 1,height++;
		data.assign(2*sz,e);
		lazy.assign(2*sz,Oe);
	}

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

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

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

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

	inline void recalc(int k) {
		while(k>>=1) data[k] = op(reflect(2*k), 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] = comp(lazy[l],x),++l;
			if(r&1) --r, lazy[r] = comp(lazy[r],x);
		}
		recalc(a);
		recalc(b);
	}

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

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

using arr = array<int,21>;

vector<int> Z_algorithm(string S){
    int M = S.size();
    vector<int> A(M,0);
    A[0] = M;
    int i = 1,j = 0;
    while(i<M){
        while(i+j<M && S[j]==S[i+j]) j++;
        A[i] = j;
        if(j==0){
            i++;
            continue;
        }
        int k = 1;
        while(i+k<M && k+A[k]<j){
            A[i+k] = A[k];
            k++;
        }
        i += k; j -= k;
    }
    return A;
}

int main(){
    cin.tie(0);
    ios::sync_with_stdio(false);
    string S;
    int N,Q;
    cin >> S >> N >> Q;
	int n = S.size();
	auto op = [&](arr L,arr R){
		arr res{};
		for(int i=0;i<=n;i++) res[i] = L[i]+R[i];
		return res;
	};

	auto homo = [&](arr S,arr f){
		arr res{};
		for(int i=0;i<=n;i++) res[f[i]] += S[i];
		return res;
	};

	auto comp = [&](arr f,arr g){
		arr res{};
		for(int i=0;i<=n;i++) res[i] = g[f[i]];
		return res;
	};

	arr id{};
	for(int i=0;i<=20;i++) id[i] = i;
	LazySegmentTree<arr,arr,decltype(op),decltype(homo),decltype(comp)>
	seg(N,op,homo,comp,arr{},id);
	for(int i=0;i<N;i++){
		arr a{};
		a[0] = 1;
		seg.set(i,a);
	}
	seg.build();

	for(int i=0;i<Q;i++){
		int t;
		cin >> t;
		if(t==1){
			int l,r;
			string c;
			cin >> l >> r >> c;
			l--; r--;
			arr f{};
			int m = c.size();
			for(int i=0;i<=n;i++){
				string s = S.substr(0,i)+c;
				vec<int> res = Z_algorithm(S+s);
				for(int j=max(i+m,n);j<n+i+m;j++){
					if(j+res[j]==n+i+m) f[i] = max(f[i],min(res[j],n));
				}
			}
//			for(int j=0;j<=n;j++) cerr << f[j] << (j!=n? " ":"\n");
			seg.update(l,r+1,f);
		}else{
			int l,r;
			cin >> l >> r;
			l--; r--;
			cout << seg.query(l,r+1)[n] << "\n";
		}
	}
}
accuracy: 1
time_ms: 1200
memory_kb: 45944
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
template<class T> using vec = vector<T>;
template<class T> using vvec = vector<vec<T>>;

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

	int sz,height;
	vec<Monoid> data;
	vec<OperatorMonoid> lazy;
	const F op;
	const G homo;
	const H comp;
  	const Monoid e;
	const OperatorMonoid Oe;

	LazySegmentTree(int n,const F op,const G homo,const H comp,
					const Monoid &e,const OperatorMonoid Oe)
		: op(op),homo(homo),comp(comp),e(e),Oe(Oe) {
		sz = 1;
		height = 0;
		while(sz<=n) sz <<= 1,height++;
		data.assign(2*sz,e);
		lazy.assign(2*sz,Oe);
	}

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

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

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

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

	inline void recalc(int k) {
		while(k>>=1) data[k] = op(reflect(2*k), 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] = comp(lazy[l],x),++l;
			if(r&1) --r, lazy[r] = comp(lazy[r],x);
		}
		recalc(a);
		recalc(b);
	}

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

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

using arr = array<int,21>;

vector<int> Z_algorithm(string S){
    int M = S.size();
    vector<int> A(M,0);
    A[0] = M;
    int i = 1,j = 0;
    while(i<M){
        while(i+j<M && S[j]==S[i+j]) j++;
        A[i] = j;
        if(j==0){
            i++;
            continue;
        }
        int k = 1;
        while(i+k<M && k+A[k]<j){
            A[i+k] = A[k];
            k++;
        }
        i += k; j -= k;
    }
    return A;
}

int main(){
    cin.tie(0);
    ios::sync_with_stdio(false);
    string S;
    int N,Q;
    cin >> S >> N >> Q;
	int n = S.size();
	vec<string> SS;
//	for(int j=0;j<=n;j++) SS[j] = S.substr(0,j);
	auto op = [&](arr L,arr R){
		arr res{};
		for(int i=0;i<=n;i++) res[i] = L[i]+R[i];
		return res;
	};

	auto homo = [&](arr S,arr f){
		arr res{};
		for(int i=0;i<=n;i++) res[f[i]] += S[i];
		return res;
	};

	auto comp = [&](arr f,arr g){
		arr res{};
		for(int i=0;i<=n;i++) res[i] = g[f[i]];
		return res;
	};

	arr id{};
	for(int i=0;i<=20;i++) id[i] = i;
	LazySegmentTree<arr,arr,decltype(op),decltype(homo),decltype(comp)>
	seg(N,op,homo,comp,arr{},id);
	for(int i=0;i<N;i++){
		arr a{};
		a[0] = 1;
		seg.set(i,a);
	}
	seg.build();

	for(int i=0;i<Q;i++){
		int t;
		cin >> t;
		if(t==1){
			int l,r;
			string c;
			cin >> l >> r >> c;
			l--; r--;
			arr f{};
			int m = c.size();
			for(int i=0;i<=n;i++){
				string s = S.substr(0,i)+c;
				vec<int> res = Z_algorithm(S+s);
				for(int j=max(n+i+m-n,n);j<n+i+m;j++){
					f[i] = max(f[i],min(res[j],n));
				}
			}
//			for(int j=0;j<=n;j++) cerr << f[j] << (j!=n? " ":"\n");
			seg.update(l,r+1,f);
		}else{
			int l,r;
			cin >> l >> r;
			l--; r--;
			cout << seg.query(l,r+1)[n] << "\n";
		}
	}
}
accuracy: 0.7777777777777778
time_ms: 440
memory_kb: 45828
final_rank: 17

code_snippet: #include <iostream>
#include <vector>
#include <array>
#include <list>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <tuple>
#include <bitset>
#include <memory>
#include <cmath>
#include <algorithm>
#include <functional>
#include <iomanip>
#include <numeric>
#include <climits>
#include <cfloat>
#include <cassert>
#include <random>




class SegTree {
	std::vector<std::vector<int>> next_position;
	std::vector<std::vector<std::vector<int>>> seg;
	std::vector<std::vector<std::vector<int>>> delay;
	std::vector<std::vector<bool>> delaied;
	std::vector<int> replacer, work_space;
	void ensure_change(int depth, int position) {
		replace_all(depth, position, replacer);
	}
	void apply_delaied(int depth, int position) {
		if (depth == 0) return;
		if (!delaied[depth][position]) return;
		replace_all(depth - 1, position * 2, delay[depth][position]);
		replace_all(depth - 1, position * 2 + 1, delay[depth][position]);
		std::iota(delay[depth][position].begin(), delay[depth][position].end(), 0);
		delaied[depth][position] = false;
	}
	void replace_all(int depth, int position, const std::vector<int>& replace) {
		std::copy(seg[depth][position].begin(), seg[depth][position].end(), work_space.begin());
		std::fill(seg[depth][position].begin(), seg[depth][position].end(), 0);
		for (auto i = 0; i < replace.size(); ++i) {
			seg[depth][position][replace[i]] += work_space[i];
		}
		if (depth == 0) return;
		for (auto& i : delay[depth][position]) i = replace[i];
		delaied[depth][position] = true;
	}
	void recalculation(int depth, int position) {
		if (depth == 0) return;
		for (auto i = 0; i < seg[depth][position].size(); ++i) {
			if (position * 2 + 1 < seg[depth - 1].size()) {
				seg[depth][position][i] = seg[depth - 1][position * 2][i] + seg[depth - 1][position * 2 + 1][i];
			}
			else {
				seg[depth][position][i] = seg[depth - 1][position * 2][i];
			}
		}
	}
	void add_inner(int depth, int from, int until) {
		if (from >= until) return;
		int length = 1 << depth;
		auto mid = (from + length - 1) / length * length;
		if (mid + length < until) {
			add_inner(depth, from, mid + length);
			add_inner(depth, mid + length, until);
			return;
		}
		if (from < mid && mid < until) {
			add_inner(depth, from, mid);
			add_inner(depth, mid, until);
			return;
		}
		if (from == mid && mid + length == until) {
			ensure_change(depth, from / length);
			return;
		}
		apply_delaied(depth, from / length);
		add_inner(depth - 1, from, until);
		recalculation(depth, from / length);
	}
	int count_inner(int depth, int from, int until) {
		if (from >= until) return 0;
		int length = 1 << depth;
		auto mid = (from + length - 1) / length * length;
		if (mid + length < until) {
			return count_inner(depth, from, mid + length) + count_inner(depth, mid + length, until);
		}
		if (from < mid && mid < until) {
			return count_inner(depth, from, mid) + count_inner(depth, mid, until);
		}
		if (from == mid && mid + length == until) {
			return seg[depth][from / length].back();
		}
		apply_delaied(depth, from / length);
		recalculation(depth, from / length);
		return count_inner(depth - 1, from, until);
	}
	void set_replacer(const std::string& str) {
		std::iota(replacer.begin(), replacer.end(), 0);
		for (const auto c : str) {
			for (auto& i : replacer) {
				i = next_position[i][c - 'a'];
			}
		}
	}
public:
	SegTree(int size, const std::string& str) : next_position(str.size() + 1, std::vector<int>(26, 0)), replacer(str.size() + 1), work_space(str.size() + 1) {
		std::vector<int> lcp(str.size(), 0);
		lcp[0] = -1;
		for (auto i = 2; i < str.size(); ++i) {
			lcp[i] = lcp[i - 1];
			while (lcp[i] != -1 && str[lcp[i]] != str[i - 1]) {
				lcp[i] = lcp[lcp[i]];
			}
			lcp[i]++;
		}
		next_position[0][str[0] - 'a'] = 1;
		for (auto i = 1; i < str.size(); ++i) {
			next_position[i] = next_position[lcp[i]];
			next_position[i][str[i] - 'a'] = i + 1;
		}
		if (lcp.back() != -1) {
			next_position[str.size()] = next_position[next_position[lcp.back()][str.back() - 'a']];
		}
		else {
			next_position[str.size()][str.back() - 'a'] = 1;
		}
		seg.emplace_back(size, std::vector<int>(str.size() + 1, 0));
		for (auto& c : seg[0]) c[0] = 1;
		delay.emplace_back(size, std::vector<int>(str.size() + 1));
		delaied.emplace_back(size);
		while (seg.back().size() > 1) {
			delay.emplace_back((seg.back().size() + 1) / 2, std::vector<int>(str.size() + 1));
			delaied.emplace_back((seg.back().size() + 1) / 2, false);
			seg.emplace_back((seg.back().size() + 1) / 2, std::vector<int>(str.size() + 1, 0));
		}
		for (auto i = 0; i + 1 < seg.size(); ++i) {
			for (auto j = 0; j < seg[i].size(); ++j) {
				seg[i + 1][j / 2][0] += seg[i][j][0];
			}
		}
	}
	void add(int from, int to, const std::string str) {
		set_replacer(str);
		add_inner(seg.size() - 1, from, to + 1);
	}
	int count(int from, int to) {
		return count_inner(seg.size() - 1, from, to + 1);
	}
};
int main() {
	std::cin.tie(0); std::cin.sync_with_stdio(false);
	std::vector<int> result;
	std::string str; std::cin >> str;
	int n, q; std::cin >> n >> q;
	SegTree seg(n, str);
	std::string c;
	for (auto i = 0; i < q; ++i) {
		int type, l, r; std::cin >> type >> l >> r;
		switch (type) {
		case 1: std::cin >> c;
			seg.add(l - 1, r - 1, c);
			break;
		case 2: std::cout << seg.count(l - 1, r - 1) << '\n';
			break;
		default: throw 0;
		}
	}
}
accuracy: 1
time_ms: 680
memory_kb: 48440
final_rank: 1

code_snippet: #include <iostream>
#include <vector>
#include <array>
#include <list>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <tuple>
#include <bitset>
#include <memory>
#include <cmath>
#include <algorithm>
#include <functional>
#include <iomanip>
#include <numeric>
#include <climits>
#include <cfloat>
#include <cassert>
#include <random>




class SegTree {
	std::vector<std::vector<int>> next_position;
	std::vector<std::vector<std::vector<int>>> seg;
	std::vector<std::vector<std::queue<char>>> delay;
	std::vector<int> work_space;
	void ensure_change(int depth, int position, const std::string &str) {
		std::copy(seg[depth][position].begin(), seg[depth][position].end(), work_space.begin());
		std::fill(seg[depth][position].begin(), seg[depth][position].end(), 0);
		for (auto i = 0; i < work_space.size(); ++i) if (work_space[i] != 0) {
			auto next = i;
			for (const auto c : str) {
				next = next_position[next][c - 'a'];
			}
			seg[depth][position][next] += work_space[i];
		}
	}
	void ensure_change(int depth, int position, char charactor) {
		std::copy(seg[depth][position].begin(), seg[depth][position].end(), work_space.begin());
		std::fill(seg[depth][position].begin(), seg[depth][position].end(), 0);
		for (auto i = 0; i < work_space.size(); ++i) {
			seg[depth][position][next_position[i][charactor - 'a']] += work_space[i];
		}
	}
	void add_str(int depth, int position, const std::string &str) {
		if (depth != 0) {
			for (auto c : str) {
				if (delay[depth][position].size() == next_position.size() - 1) delay[depth][position].pop();
				delay[depth][position].push(c);
			}
		}
		ensure_change(depth, position, str);
	}
	void add_char(int depth, int position, char charactor) {
		if (depth != 0) {
			if (delay[depth][position].size() == next_position.size() - 1) delay[depth][position].pop();
			delay[depth][position].push(charactor);
		}
		ensure_change(depth, position, charactor);
	}

	void apply_delaied(int depth, int position) {
		while (!delay[depth][position].empty()) {
			add_char(depth - 1, position * 2, delay[depth][position].front());
			add_char(depth - 1, position * 2 + 1, delay[depth][position].front());
			delay[depth][position].pop();
		}
	}
	void recalculation(int depth, int position) {
		if (depth == 0) return;
		apply_delaied(depth, position);
		for (auto i = 0; i < seg[depth][position].size(); ++i) {
			if (position * 2 + 1 < seg[depth - 1].size()) {
				seg[depth][position][i] = seg[depth - 1][position * 2][i] + seg[depth - 1][position * 2 + 1][i];
			}
			else {
				seg[depth][position][i] = seg[depth - 1][position * 2][i];
			}
		}
	}
	void add_inner(int depth, int from, int until, const std::string &str) {
		if (from >= until) return;
		int length = 1 << depth;
		auto mid = (from + length - 1) / length * length;
		if (mid + length < until) {
			add_inner(depth, from, mid + length, str);
			add_inner(depth, mid + length, until, str);
			return;
		}
		if (from < mid && mid < until) {
			add_inner(depth, from, mid, str);
			add_inner(depth, mid, until, str);
			return;
		}
		if (from == mid && mid + length == until) {
			add_str(depth, from / length, str);
			return;
		}
		apply_delaied(depth, from / length);
		add_inner(depth - 1, from, until, str);
		recalculation(depth, from / length);
	}
	int count_inner(int depth, int from, int until) {
		if (from >= until) return 0;
		int length = 1 << depth;
		auto mid = (from + length - 1) / length * length;
		if (mid + length < until) {
			return count_inner(depth, from, mid + length) + count_inner(depth, mid + length, until);
		}
		if (from < mid && mid < until) {
			return count_inner(depth, from, mid) + count_inner(depth, mid, until);
		}
		if (from == mid && mid + length == until) {
			return seg[depth][from / length].back();
		}
		recalculation(depth, from / length);
		return count_inner(depth - 1, from, until);
	}
public:
	SegTree(int size, const std::string& str) : next_position(str.size() + 1, std::vector<int>(26, 0)), work_space(str.size() + 1) {
		std::vector<int> lcp(str.size(), 0);
		lcp[0] = -1;
		for (auto i = 2; i < str.size(); ++i) {
			lcp[i] = lcp[i - 1];
			while (lcp[i] != -1 && str[lcp[i]] != str[i]) {
				lcp[i] = lcp[lcp[i]];
			}
			lcp[i]++;
		}
		next_position[0][str[0] - 'a'] = 1;
		for (auto i = 1; i < str.size(); ++i) {
			next_position[i] = next_position[lcp[i]];
			next_position[i][str[i] - 'a'] = i + 1;
		}
		if (lcp.back() != -1) {
			next_position[str.size()] = next_position[next_position[lcp.back()][str.back() - 'a']];
		}
		else {
			next_position[str.size()][str.back() - 'a'] = 1;
		}
		seg.emplace_back(size, std::vector<int>(str.size() + 1, 0));
		for (auto& c : seg[0]) c[0] = 1;
		delay.emplace_back(size);
		while (seg.back().size() > 1) {
			delay.emplace_back((seg.back().size() + 1) / 2);
			seg.emplace_back((seg.back().size() + 1) / 2, std::vector<int>(str.size() + 1, 0));
		}
		for (auto i = 0; i + 1 < seg.size(); ++i) {
			for (auto j = 0; j < seg[i].size(); ++j) {
				seg[i + 1][j / 2][0] += seg[i][j][0];
			}
		}
	}
	void add(int from, int to, const std::string str) {
		add_inner(seg.size() - 1, from, to + 1, str);
	}
	int count(int from, int to) {
		return count_inner(seg.size() - 1, from, to + 1);
	}
};
int main() {
	std::string str; std::cin >> str;
	int n, q; std::cin >> n >> q;
	SegTree seg(n, str);
	std::string c;
	for (auto i = 0; i < q; ++i) {
		int type, l, r; std::cin >> type >> l >> r;
		switch (type) {
		case 1: std::cin >> c;
			seg.add(l - 1, r - 1, c);
			break;
		case 2: std::cout << seg.count(l - 1, r - 1) << '\n';
			break;
		default: throw 0;
		}
	}
}
accuracy: 0.7777777777777778
time_ms: 990
memory_kb: 144484
final_rank: 19

code_snippet: #include <iostream>
#include <vector>
#include <array>
#include <list>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <tuple>
#include <bitset>
#include <memory>
#include <cmath>
#include <algorithm>
#include <functional>
#include <iomanip>
#include <numeric>
#include <climits>
#include <cfloat>
#include <cassert>
#include <random>




class SegTree {
	std::vector<std::vector<int>> next_position;
	std::vector<std::vector<std::vector<int>>> seg;
	std::vector<std::vector<std::queue<char>>> delay;
	std::vector<int> work_space;
	void ensure_change(int depth, int position, const std::string &str) {
		std::copy(seg[depth][position].begin(), seg[depth][position].end(), work_space.begin());
		std::fill(seg[depth][position].begin(), seg[depth][position].end(), 0);
		for (auto i = 0; i < work_space.size(); ++i) if (work_space[i] != 0) {
			auto next = i;
			for (const auto c : str) {
				next = next_position[next][c - 'a'];
			}
			seg[depth][position][next] += work_space[i];
		}
	}
	void ensure_change(int depth, int position, char charactor) {
		std::copy(seg[depth][position].begin(), seg[depth][position].end(), work_space.begin());
		std::fill(seg[depth][position].begin(), seg[depth][position].end(), 0);
		for (auto i = 0; i < work_space.size(); ++i) {
			seg[depth][position][next_position[i][charactor - 'a']] += work_space[i];
		}
	}
	void add_str(int depth, int position, const std::string &str) {
		if (depth != 0) {
			for (auto c : str) {
				if (delay[depth][position].size() == next_position.size() - 1) delay[depth][position].pop();
				delay[depth][position].push(c);
			}
		}
		ensure_change(depth, position, str);
	}
	void add_char(int depth, int position, char charactor) {
		if (depth != 0) {
			if (delay[depth][position].size() == next_position.size() - 1) delay[depth][position].pop();
			delay[depth][position].push(charactor);
		}
		ensure_change(depth, position, charactor);
	}

	void apply_delaied(int depth, int position) {
		while (!delay[depth][position].empty()) {
			add_char(depth - 1, position * 2, delay[depth][position].front());
			add_char(depth - 1, position * 2 + 1, delay[depth][position].front());
			delay[depth][position].pop();
		}
	}
	void recalculation(int depth, int position) {
		if (depth == 0) return;
		apply_delaied(depth, position);
		for (auto i = 0; i < seg[depth][position].size(); ++i) {
			if (position * 2 + 1 < seg[depth - 1].size()) {
				seg[depth][position][i] = seg[depth - 1][position * 2][i] + seg[depth - 1][position * 2 + 1][i];
			}
			else {
				seg[depth][position][i] = seg[depth - 1][position * 2][i];
			}
		}
	}
	void add_inner(int depth, int from, int until, const std::string &str) {
		if (from >= until) return;
		int length = 1 << depth;
		auto mid = (from + length - 1) / length * length;
		if (mid + length < until) {
			add_inner(depth, from, mid + length, str);
			add_inner(depth, mid + length, until, str);
			return;
		}
		if (from < mid && mid < until) {
			add_inner(depth, from, mid, str);
			add_inner(depth, mid, until, str);
			return;
		}
		if (from == mid && mid + length == until) {
			add_str(depth, from / length, str);
			return;
		}
		apply_delaied(depth, from / length);
		add_inner(depth - 1, from, until, str);
		recalculation(depth, from / length);
	}
	int count_inner(int depth, int from, int until) {
		if (from >= until) return 0;
		int length = 1 << depth;
		auto mid = (from + length - 1) / length * length;
		if (mid + length < until) {
			return count_inner(depth, from, mid + length) + count_inner(depth, mid + length, until);
		}
		if (from < mid && mid < until) {
			return count_inner(depth, from, mid) + count_inner(depth, mid, until);
		}
		if (from == mid && mid + length == until) {
			return seg[depth][from / length].back();
		}
		recalculation(depth, from / length);
		return count_inner(depth - 1, from, until);
	}
public:
	SegTree(int size, const std::string& str) : next_position(str.size() + 1, std::vector<int>(26, 0)), work_space(str.size() + 1) {
		std::vector<int> lcp(str.size(), 0);
		lcp[0] = -1;
		for (auto i = 2; i < str.size(); ++i) {
			lcp[i] = lcp[i - 1];
			while (lcp[i] != -1 && str[lcp[i]] != str[i]) {
				lcp[i] = lcp[lcp[i]];
			}
			lcp[i]++;
		}
		next_position[0][str[0] - 'a'] = 1;
		for (auto i = 1; i < str.size(); ++i) {
			next_position[i] = next_position[lcp[i]];
			next_position[i][str[i] - 'a'] = i + 1;
		}
		next_position[str.size()] = next_position[next_position[lcp.back()][str.back() - 'a']];
		seg.emplace_back(size, std::vector<int>(str.size() + 1, 0));
		for (auto& c : seg[0]) c[0] = 1;
		delay.emplace_back(size);
		while (seg.back().size() > 1) {
			delay.emplace_back((seg.back().size() + 1) / 2);
			seg.emplace_back((seg.back().size() + 1) / 2, std::vector<int>(str.size() + 1, 0));
		}
		for (auto i = 0; i + 1 < seg.size(); ++i) {
			for (auto j = 0; j < seg[i].size(); ++j) {
				seg[i + 1][j / 2][0] += seg[i][j][0];
			}
		}
	}
	void add(int from, int to, const std::string str) {
		add_inner(seg.size() - 1, from, to + 1, str);
	}
	int count(int from, int to) {
		return count_inner(seg.size() - 1, from, to + 1);
	}
};
int main() {
	std::string str; std::cin >> str;
	int n, q; std::cin >> n >> q;
	SegTree seg(n, str);
	std::string c;
	for (auto i = 0; i < q; ++i) {
		int type, l, r; std::cin >> type >> l >> r;
		switch (type) {
		case 1: std::cin >> c;
			seg.add(l - 1, r - 1, c);
			break;
		case 2: std::cout << seg.count(l - 1, r - 1) << '\n';
			break;
		default: throw 0;
		}
	}
}
accuracy: 0.6944444444444444
time_ms: 850
memory_kb: 144640
final_rank: 20

code_snippet: #include <iostream>
#include <string>
#include <vector>

using namespace std;

int len;

void ident(vector<int> &vec)
{
	for(int i = 0; i <= len; i++) vec[i] = i;
}
void ope(vector<int> &vec, vector<int> &op)
{
	vector<int> tmp = vec;
	//cout << "VEC "; for(int i = 0; i <= len; i++) cout << vec[i] << " "; cout << endl;
	//cout << "OP "; for(int i = 0; i <= len; i++) cout << op[i] << " "; cout << endl;
	for(int i = 0; i <= len; i++) vec[i] = 0;
	for(int i = 0; i <= len; i++) vec[op[i]] += tmp[i];
	//cout << "ANS "; for(int i = 0; i <= len; i++) cout << vec[i] << " "; cout << endl;
}
void mul(vector<int> &op, vector<int> &op2)
{
	vector<int> tmp = op;
	for(int i = 0; i <= len; i++) op[i] = op2[tmp[i]];
}
void merge(vector<int> &dest, vector<int> &src, vector<int> &src2)
{
	for(int i = 0; i <= len; i++) dest[i] = src[i] + src2[i];
}

struct SegTree{
	int size;
	vector<vector<int> > seg, delay;
	vector<int> flag;
	
	SegTree(){}
	SegTree(int size){
		this->size = size;
		seg.resize(1<<(size+1));
		delay.resize(1<<(size+1));
		for(int i = 0; i < (1<<(size+1)); i++){
			seg[i].resize(len+1);
			delay[i].resize(len+1);
		}
		flag.resize(1<<(size+1));
	}
	
	void init()
	{
		for(int i = 0; i < (1<<(size+1)); i++) ident(delay[i]);
	}
	
	void eval(int l, int r, int k)
	{
		if(flag[k]){
			ope(seg[k], delay[k]);
			if(l < r){
				mul(delay[k*2], delay[k]), flag[k*2] = true;
				mul(delay[k*2+1], delay[k]), flag[k*2+1] = true;
			}
			ident(delay[k]);
			flag[k] = false;
		}
	}
	
	void update(int i)
	{
		i += (1 << size);
		seg[i][0] = 1;
		while(i > 1){
			i /= 2;
			seg[i][0] = seg[i*2][0] + seg[i*2+1][0];
		}
	}
	
	void add(int a, int b, int k, int l, int r, vector<int> &val)
	{
		eval(l, r, k);
		
		if(b < l || r < a) return;
		if(a <= l && r <= b){
			mul(delay[k], val);
			flag[k] = true;
			eval(l, r, k);
			return;
		}
		add(a, b, k*2, l, (l+r)/2, val);
		add(a, b, k*2+1, (l+r)/2+1, r, val);
		merge(seg[k], seg[k*2], seg[k*2+1]);
	}
	void add(int a, int b, vector<int> &val){
		if(a > b) return;
		add(a, b, 1, 0, (1<<size)-1, val);
	}
 
	int query(int a, int b, int k, int l, int r)
	{
		eval(l, r, k);
		
		if(b < l || r < a) return 0;
		if(a <= l && r <= b) return seg[k][len];
		int lval = query(a, b, k*2, l, (l+r)/2);
		int rval = query(a, b, k*2+1, (l+r)/2+1, r);
		return lval + rval;
	}
	int query(int a, int b)
	{
		return query(a, b, 1, 0, (1<<size)-1);
	}
};

string s;
int n, Q;
int succ[25][26];
SegTree seg;

void get(vector<int> &vec, char c)
{
	for(int i = 0; i <= len; i++) vec[i] = succ[i][c-'a'];
}

int main(void)
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	
	cin >> s;
	cin >> n >> Q;
	
	len = s.size();
	seg = SegTree(17);
	for(int i = 1; i <= n; i++) seg.update(i);
	
	for(int i = 0; i <= len; i++){
		for(int j = 0; j < 26; j++){
			string t = s.substr(0, i) + (char)(j+'a');
			int k = t.size();
			for(; k >= 0; k--){
				if(t == s.substr(0, k)) break;
				t = t.substr(1);
			}
			succ[i][j] = k;
		}
	}
	
	int t, l, r; string str;
	vector<int> vec(len+1), op(len+1);
	
	seg.init();
	
	for(int q = 0; q < Q; q++){
		cin >> t >> l >> r;
		if(t == 1){
			cin >> str;
			ident(vec);
			for(int i = 0; i < str.size(); i++){
				get(op, str[i]);
				mul(vec, op);
			}
			//for(int i = 0; i <= len; i++) cout << vec[i] << " "; cout << endl;
			seg.add(l, r, vec);
			/*for(int i = 1; i <= n; i++){
				cout << "["; for(int j = 0; j <= len; j++) cout << seg.seg[(1<<17)+i][j]; cout << "] ";
			}
			cout << endl;*/
		}
		else cout << seg.query(l, r) << "\n";
	}
	flush(cout);
	
	return 0;
}
accuracy: 1
time_ms: 1340
memory_kb: 127700
final_rank: 9

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}


struct FastIO{
  FastIO(){
    cin.tie(0);
    ios::sync_with_stdio(0);
  }
}fastio_beet;


template<size_t X>
struct Trie{
  struct Node{
    char c;
    array<int, X> nxt;
    vector<int> idxs;
    int idx;
    Node(char c):c(c),idx(-1){fill(nxt.begin(),nxt.end(),-1);}
  };

  using F = function<int(char)>;
  vector<Node> v;
  F conv;

  Trie(F conv,char c='$'):conv(conv){v.emplace_back(c);}

  void add(const string &s,int x){
    int pos=0;
    for(int i=0;i<(int)s.size();i++){
      int k=conv(s[i]);
      if(~v[pos].nxt[k]){
        pos=v[pos].nxt[k];
        continue;
      }
      int npos=v.size();
      v[pos].nxt[k]=npos;
      v.emplace_back(s[i]);
      pos=npos;
    }
    v[pos].idx=x;
    v[pos].idxs.emplace_back(x);
  }

  int find(const string &s){
    int pos=0;
    for(int i=0;i<(int)s.size();i++){
      int k=conv(s[i]);
      if(v[pos].nxt[k]<0) return -1;
      pos=v[pos].nxt[k];
    }
    return pos;
  }

  int find(int pos,char c){
    return v[pos].nxt[conv(c)];
  }

  int idx(int pos){
    return pos<0?-1:v[pos].idx;
  }

  vector<int> idxs(int pos){
    return pos<0?vector<int>():v[pos].idxs;
  }

};

template<size_t X>
struct AhoCorasick : Trie<X+1>{
  using TRIE = Trie<X+1>;
  using TRIE::TRIE;
  vector<int> cnt;

  void build(bool heavy=true){
    auto &v=TRIE::v;
    int n=v.size();
    cnt.resize(n);
    for(int i=0;i<n;i++){
      if(heavy) sort(v[i].idxs.begin(),v[i].idxs.end());
      cnt[i]=v[i].idxs.size();
    }

    queue<int> q;
    for(int i=0;i<(int)X;i++){
      if(~v[0].nxt[i]){
        v[v[0].nxt[i]].nxt[X]=0;
        q.emplace(v[0].nxt[i]);
      }else{
        v[0].nxt[i]=0;
      }
    }

    while(!q.empty()){
      auto &x=v[q.front()];
      cnt[q.front()]+=cnt[x.nxt[X]];
      q.pop();
      for(int i=0;i<(int)X;i++){
        if(x.nxt[i]<0) continue;
        int fail=x.nxt[X];
        while(v[fail].nxt[i]<0) fail=v[fail].nxt[X];
        v[x.nxt[i]].nxt[X]=v[fail].nxt[i];
        if(heavy){
          auto &idx=v[x.nxt[i]].idxs;
          auto &idy=v[v[fail].nxt[i]].idxs;
          vector<int> idz;
          set_union(idx.begin(),idx.end(),
                    idy.begin(),idy.end(),
                    back_inserter(idz));
          idx=idz;
        }
        q.emplace(x.nxt[i]);
      }
    }
  }

  vector<int> match(string s,int heavy=true){
    auto &v=TRIE::v;
    vector<int> res(heavy?TRIE::size():1);
    int pos=0;
    for(auto &c:s){
      int k=TRIE::conv(c);
      while(v[pos].nxt[k]<0) pos=v[pos].nxt[X];
      pos=v[pos].nxt[k];
      if(heavy) for(auto &x:v[pos].idxs) res[x]++;
      else res[0]+=cnt[pos];
    }
    return res;
  }

  int move(int pos,char c){
    auto &v=TRIE::v;
    if(pos>=(int)v.size()) return pos;
    int k=TRIE::conv(c);
    while(v[pos].nxt[k]<0) pos=v[pos].nxt[X];
    pos=v[pos].nxt[k];
    return pos;
  }

  int count(int pos){
    return pos<(int)cnt.size()?cnt[pos]:0;
  }
};



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)>;
  int n,height;
  F f;
  G g;
  H h;
  T ti;
  E ei;
  vector<T> dat;
  vector<E> laz;
  SegmentTree(F f,G g,H h,T ti,E ei):
    f(f),g(g),h(h),ti(ti),ei(ei){}

  void init(int n_){
    n=1;height=0;
    while(n<n_) n<<=1,height++;
    dat.assign(2*n,ti);
    laz.assign(2*n,ei);
  }
  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 T reflect(int k){
    return laz[k]==ei?dat[k]:g(dat[k],laz[k]);
  }
  inline void eval(int k){
    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);
    laz[k]=ei;
  }
  inline void thrust(int k){
    for(int i=height;i;i--) eval(k>>i);
  }
  inline void recalc(int k){
    while(k>>=1)
      dat[k]=f(reflect((k<<1)|0),reflect((k<<1)|1));
  }
  void update(int a,int b,E x){
    thrust(a+=n);
    thrust(b+=n-1);
    for(int l=a,r=b+1;l<r;l>>=1,r>>=1){
      if(l&1) laz[l]=h(laz[l],x),l++;
      if(r&1) --r,laz[r]=h(laz[r],x);
    }
    recalc(a);
    recalc(b);
  }
  void set_val(int a,T x){
    thrust(a+=n);
    dat[a]=x;laz[a]=ei;
    recalc(a);
  }
  T query(int a,int b){
    thrust(a+=n);
    thrust(b+=n-1);
    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;
    }
    eval(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);
  }
};

//INSERT ABOVE HERE
signed main(){

  string s;
  cin>>s;
  int n,q;
  cin>>n>>q;

  auto conv=[](char c){return c-'a';};
  AhoCorasick<26> aho(conv);
  aho.add(s,0);
  aho.build(false);

  using A = array<int, 32>;
  A ti,ei;
  fill(ti.begin(),ti.end(),0);
  iota(ei.begin(),ei.end(),0);
  auto f=[&](A a,A b){
           A c;
           for(int i=0;i<(int)a.size();i++) c[i]=a[i]+b[i];
           return c;
         };
  auto g=[&](A a,A b){
           A c(ti);
           for(int i=0;i<(int)a.size();i++) c[b[i]]+=a[i];
           return c;
         };
  auto h=[&](A a,A b){
           A c;
           for(int i=0;i<(int)a.size();i++) c[i]=b[a[i]];
           return c;
         };
  SegmentTree<A, A> seg(f,g,h,ti,ei);
  vector<A> va(n,ti);
  for(int i=0;i<n;i++) va[i][0]=1;
  seg.build(va);

  vector<A> mv(26);
  for(int x=0;x<26;x++){
    for(int i=0;i<(int)mv[x].size();i++)
      mv[x][i]=aho.move(i,char('a'+x));
  }

  for(int i=0;i<q;i++){
    int t;
    cin>>t;
    if(t==1){
      int l,r;
      string c;
      cin>>l>>r>>c;
      l--;
      A a=ei;
      for(char x:c) a=h(a,mv[x-'a']);
      seg.update(l,r,a);
      //for(char x:c) seg.update(l,r,mv[x-'a']);
    }
    if(t==2){
      int l,r;
      cin>>l>>r;
      l--;
      A res=seg.query(l,r);
      int ans=0;
      for(int j=0;j<(int)res.size();j++)
        if(aho.count(j)) ans+=res[j];
      cout<<ans<<"\n";
    }
  }
  cout<<flush;
  return 0;
}
accuracy: 1
time_ms: 1020
memory_kb: 80840
final_rank: 7

code_snippet: #include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>

#include <iostream>
#include <complex>
#include <string>
#include <algorithm>
#include <numeric>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>

#include <functional>
#include <cassert>

typedef long long ll;
using namespace std;

#ifndef LOCAL
#define debug(x) ;
#else
#define debug(x) cerr << __LINE__ << " : " << #x << " = " << (x) << endl;

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

template <typename T>
ostream &operator<<(ostream &out, const vector<T> &v) {
  out << '{';
  for (const T &item : v) out << item << ", ";
  out << "\b\b}";
  return out;
}
#endif

#define mod 1000000007 //1e9+7(prime number)
#define INF 1000000000 //1e9
#define LLINF 2000000000000000000LL //2e18
#define SIZE 200010

/* Aho Corasick */

struct ACNode{
  int val;
  ACNode *next[26], *failure;
  int id;

  ACNode():val(0) { memset(next, 0, sizeof(next)); }

  void insert(char *s, int _id){
    id = _id;
    if(!*s){ val++; return; }
    int al = *s - 'a';
    if(next[al] == NULL) next[al] = new ACNode;
    next[al]->insert(s+1, _id+1);
  }

  ACNode *nextNode(char c){
    int al = c - 'a';
    if (next[al]) return next[al];
    return failure == this ? this : failure->nextNode(c);
  }
};

struct AhoCorasick{
  ACNode *node;

  AhoCorasick(){node = new ACNode;}

  void insert(char *s) {
    node->insert(s, 0);
  }

  void build() {
    queue<ACNode*> que;
    que.push(node);
    node->failure = node;

    while(que.size()){
      ACNode *p = que.front();
      que.pop();

      for(int i=0;i<26;i++){
        if(p->next[i]){
          ACNode *failure = p->failure;
          while(!failure->next[i] && failure != node)
            failure = failure->failure;

          if (failure->next[i] && failure != p){
            p->next[i]->failure = failure->next[i];
            p->next[i]->val += failure->next[i]->val;
          }else{
            p->next[i]->failure = node;
          }
          que.push(p->next[i]);
        }
      }
    }
  }
};

vector<int> apply(vector<int> &a, vector<int> &b) {
  vector<int> res;

  assert(a.size() == b.size());

  for(int i=0; i<a.size(); i++) {
    res.push_back(b[a[i]]);
  }

  return res;
}

vector<int> apply2(vector<int> &a, vector<int> &b) {
  vector<int> res(a.size(), 0);
  assert(a.size() == b.size());

  for(int i=0; i<a.size(); i++) {
    res[b[i]] += a[i];
  }

  return res;
}

/* SegmentTree(Sum) */
//0-index

struct SegTree{
  int segn2;
  vector<vector<int> > data;
  vector<vector<int> > rep;
  vector<int> base;

  vector<int> merge(vector<int> &a, vector<int> &b) {
    vector<int> res = a;

    for(int i=0; i<a.size(); i++)
      res[i] += b[i];

    return res;
  }

  SegTree(int n, int m){
    for(segn2=1; segn2<n; segn2*=2);

    vector<int> v(m);

    data.assign(segn2*2, v);

    v[0] = 1;

    for(int i=segn2-1; i<segn2-1+n; i++) {
      data[i] = v;
    }

    for(int i=segn2-2; i>=0; i--) {
      data[i] = merge(data[i*2+1], data[i*2+2]);
    }

    base.assign(m, 0);
    iota(base.begin(), base.end(), 0);
    rep.assign(segn2*2, base);
  }

  //get sum of [a, b)
  vector<int> query(int a, int b, int l = 0, int r = -1, int k = 0){
    if(r == -1) r = segn2;

    if(r <= a || b <= l) return vector<int>(data[k].size(), 0);
    if(a <= l && r <= b) return data[k];

    auto res1 = query(a, b, l, (l+r)/2, k*2+1);
    auto res2 =  query(a, b, (l+r)/2, r, k*2+2);
    auto res12 = merge( res1, res2 );

    return apply2(res12, rep[k]);
  }

  //add x to [a, b)
  void add(int a, int b, vector<int> &x, vector<int> &u, int l = 0, int r = -1, int k = 0){
    if(r == -1) r = segn2;

    rep[k] = apply(rep[k], u);

    vector<int> res1, res2;

    if(a <= l && r <= b) {
      rep[k] = apply(rep[k], x);
      data[k] = apply2(data[k], u);
      data[k] = apply2(data[k], x);
    } else if(a < r && l < b) {
      add(a, b, x, rep[k], l, (l+r)/2, k*2+1);
      add(a, b, x, rep[k], (l+r)/2, r, k*2+2);
      rep[k] = base;
      auto v = merge(data[k*2+1], data[k*2+2]);
      data[k] = v;
    } else {
      data[k] = apply2(data[k], u);
    }
  }
};

int main(){
  char S[21];
  int N, Q, M;

  ACNode *start[21];

  scanf("%s%d%d", S, &N, &Q);
  M = strlen(S);

  AhoCorasick aho;

  aho.insert(S);
  aho.build();

  start[0] = aho.node;

  SegTree seg(N, M+1);

  for(int i=0; i<M; i++) {
    start[i+1] = start[i]->nextNode(S[i]);
  }


  for(int i=0; i<Q; i++) {
    int q, l, r;
    char c[11];

    scanf("%d%d%d", &q, &l, &r);
    l--;

    if(q == 1) {
      scanf("%s", c);

      vector<int> vec;
      for(int j=0; j<=M; j++) {
        ACNode *p = start[j];

        for(int k=0; c[k]; k++) {
          p = p->nextNode(c[k]);
        }
        vec.push_back(p->id);
      }

      seg.add(l, r, vec, seg.base);
    } else {
      vector<int> res = seg.query(l, r);
      printf("%d\n", res[M]);
    }
  }


  return 0;
}
accuracy: 1
time_ms: 2430
memory_kb: 80836
final_rank: 10