#include using namespace std; typedef long long LL; const LL MOD = 1000000007LL; const int MAXN = 100009; typedef struct Node { int cnt[26]; bool flag = false; LL shift = 0LL; } node; node tree[4*MAXN]; int n; char s[MAXN]; node merger(node left, node right) { node x; for (int i = 0; i < 26; i ++) { x.cnt[i] = left.cnt[i] + right.cnt[i]; } return x; } void shifter(int* arr, LL value) { int b[26]; for (int i = 0; i < 26; i ++) { b[i] = arr[i]; } for (int i = 0; i < 26; i ++) { int newIndex = ((i + value) % 26); arr[newIndex] = b[i]; } } void build(int index, int start, int en) { if(start == en) { for (int i = 0; i < 26; i ++) { tree[index].cnt[i] = 0; } tree[index].cnt[s[start] - 'a'] = 1; return; } else if(start < en) { int mid = (start + en)/2; build(2 * index, start, mid); build(2 * index + 1, mid + 1, en); tree[index] = merger(tree[2 * index], tree[2 * index + 1]); } } void update(int index, int i, int j, int start, int en, LL data) { if(start > en or i > en or j < start) return; if(start >= i and en <= j) { tree[index].flag = true; tree[index].shift += data; shifter(tree[index].cnt, data); return; } if(tree[index].flag) { //reset tree[index].flag = false; int mid = ( start + en ) / 2; LL shift = tree[index].shift; tree[index].shift = 0LL; //push tree[2*index].flag = true; shifter(tree[2 * index].cnt, shift); tree[2*index].shift += shift; //push tree[2*index + 1].flag = true; shifter(tree[2*index + 1].cnt, shift); tree[2*index + 1].shift += shift; } int mid = (start + en) / 2; update(2 * index, i, j, start, mid, data); update(2 * index + 1, i, j, mid + 1, en, data); tree[index] = merger(tree[2 * index], tree[2 * index + 1]); } void update(int i, int j, int n, LL data) { update(1, i, j, 0, n - 1, data); } node tmp; node query(int index, int i, int j, int start, int en) { if(start > en or i > en or j < start) return tmp; if(start >= i && en <= j) return tree[index]; if(tree[index].flag) { //reset tree[index].flag = false; int mid = ( start + en ) / 2; LL shift = tree[index].shift; tree[index].shift = 0LL; //push tree[2*index].flag = true; shifter(tree[2 * index].cnt, shift); tree[2*index].shift += shift; //push tree[2*index + 1].flag = true; shifter(tree[2*index + 1].cnt, shift); tree[2*index + 1].shift += shift; } int mid = (start + en) / 2; node ans = merger(query(2 * index, i, j, start, mid), query(2 * index + 1, i, j, mid + 1, en)); return ans; } LL power(LL exp) { if (exp == 0) { return 1LL; } else if (exp == 1) { return 2LL; } LL x = power(exp / 2LL); x = (x * x) % MOD; if (exp % 2 == 1) { x = (x * 2) % MOD; } return x; } LL solve(int* arr) { LL pref[28]; LL suff[28]; pref[0] = 1LL; suff[27] = 1LL; for (int i = 0; i < 26; i ++) { if (arr[i] >= 1) { pref[i + 1] = power(arr[i] - 1); } else { pref[i + 1] = 1; } pref[i + 1] = (pref[i] * pref[i + 1]) % MOD; } for (int i = 25; i >= 0; i --) { if (arr[i] >= 1) { suff[i + 1] = power(arr[i] - 1); } else { suff[i + 1] = 1LL; } suff[i + 1] = (suff[i + 2] * suff[i + 1]) % MOD; } LL ans = (pref[26] - 1 + MOD) % MOD; for (int i = 1; i <= 26; i ++) { if (arr[i - 1] >= 1) { LL curr = (pref[i - 1] * suff[i + 1]) % MOD; curr = (curr * power(arr[i - 1] - 1)) % MOD; ans = (ans + curr) % MOD; } } return ans; } int main() { for (int i = 0; i < 26; i ++) { tmp.cnt[i] = 0; } int n, q; scanf("%d%d", &n, &q); scanf("%s", s); build(1, 0, n - 1); int code; int st, en; LL val; while (q--) { scanf("%d", &code); scanf("%d%d", &st, &en); if (code == 1) { scanf("%lld", &val); update(st, en, n, val); } else { node curr = query(1, st, en, 0, n - 1); printf("%lld\n", solve(curr.cnt)); } } return 0; }