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


Measured memory_bytes: 48440