#include #define FOR(i,b,e) for(int i=(b); i <= (e); ++i) #define FORD(i,b,e) for(int i=(b); i >= (e); --i) #define SIZE(c) (int) (c).size() #define FORE(i,c) FOR(i,0,SIZE(c)-1) #define FORDE(i,c) FORD(i,SIZE(c)-1,0) #define pb push_back #define mp make_pair #define st first #define nd second using namespace std; typedef long long ll; typedef pair pii; typedef pair pll; typedef vector VI; typedef vector VB; typedef vector VP; typedef vector VL; typedef vector VPL; typedef vector VVI; typedef vector VVL; typedef vector VVB; typedef vector VVP; const int MOD = 1000000007; const int INF = 1000000001; const ll LINF = 1000000000000000001LL; const int ALPH = 'z' - 'a' + 1; struct info { int cnt[ALPH]; info() { FOR(i,0,ALPH-1) cnt[i] = 0; } }; typedef info val_t; typedef int mod_t; val_t apply(val_t v, mod_t m) { info ans; FOR(i,0,ALPH-1) { int j = (i + m) % ALPH; ans.cnt[j] = v.cnt[i]; } return ans; } mod_t buff(mod_t a, mod_t b) { return a + b; } val_t sum(val_t a, val_t b) { info ans; FOR(i,0,ALPH-1) { ans.cnt[i] = a.cnt[i] + b.cnt[i]; } return ans; } const val_t VAL_INIT = info(); const mod_t MOD_ZERO = 0; struct LazyTree { int p = 1; vector < val_t > V; vector < mod_t > M; LazyTree(int n, VI &seq) { p = 1; while (p < n) p *= 2; int m = 2 * p - 1; V.resize(m, VAL_INIT); M.resize(m, MOD_ZERO); FOR(i,0,n-1) { int v = i + p - 1; V[v].cnt[seq[i]] = 1; } FORD(i,p-2,0) V[i] = sum(V[2 * i + 1], V[2 * i + 2]); } void modify(int x, int y, mod_t m) { _modify(0, 0, p-1, x, y, m); } // applies m on [x, y] val_t query(int x, int y) { return _query(0, 0, p-1, x, y); } // gets val_t of [x, y] void _buff(int u, mod_t m) { M[u] = buff(M[u], m); } void _push(int u) { V[u] = apply(V[u], M[u]); if(u < p-1) { _buff(2 * u + 1, M[u]); _buff(2 * u + 2, M[u]); } M[u] = MOD_ZERO; } void _modify(int u, int a, int b, int x, int y, mod_t m) { _push(u); if(x <= a && b <= y) { _buff(u, m); _push(u); return ; } int mid = (a + b) / 2; if (x <= mid) _modify(2 * u + 1, a, mid, x, y, m); else _push(2 * u + 1); if (mid < y) _modify(2 * u + 2, mid + 1, b, x, y, m); else _push(2 * u + 2); V[u] = sum(V[2 * u + 1], V[2 * u + 2]); } val_t _query(int u, int a, int b, int x, int y) { _push(u); if(x <= a && b <= y) { return V[u]; } int mid = (a + b) / 2; if (y <= mid) { return _query(2 * u + 1, a, mid, x, y); } else if (mid < x) { return _query(2 * u + 2, mid + 1, b, x, y); } else { return sum(_query(2 * u + 1, a, mid, x, y), _query(2 * u + 2, mid + 1, b, x, y)); } } }; /*************************************************************************/ int main() { ios_base::sync_with_stdio(0); int n, q; cin >> n >> q; VI seq(n); FOR(i,0,n-1) { char c; cin >> c; seq[i] = c - 'a'; } LazyTree tree(n, seq); ll powTwo[n+1]; powTwo[0] = 1; FOR(i,1,n) { powTwo[i] = (2 * powTwo[i-1]) % MOD; } while (q--) { int type; cin >> type; if (type == 1) { int i, j, t; cin >> i >> j >> t; t %= ALPH; tree.modify(i, j, t); } else { int i, j; cin >> i >> j; auto res = tree.query(i, j); ll ans = 0; int cntNonzero = 0; int sumNonzero = 0; FOR(i,0,ALPH-1) if (res.cnt[i]) { cntNonzero++; sumNonzero += res.cnt[i]; } if (cntNonzero) { ans = (cntNonzero + 1) * powTwo[sumNonzero - cntNonzero]; ans %= MOD; ans = (ans + MOD - 1) % MOD; } cout << ans << '\n'; } } return 0; } /*************************************************************************/