#include using namespace std; #define sd(x) scanf("%d", &x) #define boost ios_base::sync_with_stdio(false); #define mp make_pair #define pb push_back #define all(a) a.begin(), a.end() #define f first #define s second #define TRACE #ifdef TRACE #define trace(...) __f(#__VA_ARGS__, __VA_ARGS__) template void __f(const char* name, Arg1&& arg1) { cerr << name << " : " << arg1 << endl; } template void __f(const char* names, Arg1&& arg1, Args&&... args) { const char* comma = strchr(names + 1, ','); cerr.write(names, comma - names) << " : " << arg1<<" | "; __f(comma+1, args...); } #else #define trace(...) #endif typedef pair pii; typedef long long ll; typedef vector > matrix; const int mod = 1000000007; const int inf = 50000000; const int maxn = 100010; const int maxc = 26; ll modpow(ll a, ll b) { if (b < 0) { return 1; } ll x = 1, y = a; while (b) { if (b&1) x = (x * y) % mod; y = (y * y) % mod; b >>= 1; } return x; } struct node { char val; int priority, sz, cnt[maxc], lazy; node* l; node* r; node(char x){ this->val = x; this->priority = rand(); this->l = this->r = NULL; this->sz = 1; this->lazy = 0; for (int i = 0; i < maxc; i++) { this->cnt[i] = 0; } this->cnt[x - 'a'] += 1; } }; node* treap = NULL; char str[maxn]; int n, A[maxc]; void update_sz(node* T) { if (T) { T->sz = ((T->l)?T->l->sz:0) + ((T->r)?T->r->sz:0) + 1; for (int i = 0; i < maxc; i++) { T->cnt[i] = ((T->l) ? (T->l->cnt[i]) : 0) + ((T->r) ? (T->r->cnt[i]) : 0); } T->cnt[T->val - 'a'] += 1; } } void push(node* &T) { if (T && T->lazy) { T->lazy %= maxc; for (int i = 0; i < maxc; i++) { T->cnt[i] = T->cnt[(i - T->lazy + maxc) % maxc]; } if (T->l) { T->l->lazy = (T->l->lazy + T->lazy) % maxc; } if(T->r) { T->r->lazy = (T->r->lazy + T->lazy) % maxc; } } } // x will contain <= k elements after the split void split(node* T, node* &x, node* &y, int k) { push(T); if (!T) { x = y = NULL; return; } int l_sz = 1 + ((T->l)?T->l->sz:0); if (l_sz <= k) { split(T->r, T->r, y, k-l_sz); x = T; } else { split(T->l, x, T->l, k); y = T; } update_sz(x); update_sz(y); } void merge(node* &T, node* x, node* y) { push(x); push(y); if (!x || !y) { T = x?x:y; return; } if (x->priority > y->priority) { merge(x->r, x->r, y); T = x; } else { merge(y->l, x, y->l); T = y; } update_sz(T); } void inorder(node* T) { if (!T) { return; } inorder(T->l); cout << T->val; for (int i = 0; i < maxc; i++) { trace(i, T->cnt[i]); } inorder(T->r); } void delete_treap(node* T) { if(T){ if(T->l) delete_treap(T->l); if(T->r) delete_treap(T->r); delete T; } } ll solve() { ll ret = 0, temp = 1, hold; for (int i = 0; i < maxc; i++) { // trace(i, A[i]); temp = (temp * modpow(2, A[i] - 1)) % mod; } ret = (temp - 1 + mod) % mod; for (int i = 0; i < maxc; i++) { if (A[i] == 0) { continue; } ll k = modpow(2, A[i] - 1); hold = (temp * modpow(k, mod - 2)); hold = (hold * k) % mod; ret = (ret + hold) % mod; } return ret; } int main() { //freopen("i.txt", "r", stdin); //freopen("o.txt", "w", stdout); int q, t, l, r, c; scanf("%d %d %s", &n, &q, str + 1); for (int i = 1; i <= n; i++) { node* temp = new node(str[i]); merge(treap, treap, temp); } // inorder(treap); node* L; node* R; node* mid; node* dummy; while (q--) { scanf("%d %d %d", &t, &l, &r); l += 1; r += 1; if (t == 1) { scanf("%d", &c); c %= maxc; split(treap, L, mid, l - 1); split(mid, dummy, R, r - l + 1); dummy->lazy = (dummy->lazy + c) % maxc; merge(mid, dummy, R); merge(treap, L, mid); } else { split(treap, L, mid, l - 1); split(mid, dummy, R, r - l + 1); for (int i = 0; i < maxc; i++) { A[i] = dummy->cnt[i]; } // inorder(dummy); ll ans = solve(); printf("%lld\n", ans); merge(mid, dummy, R); merge(treap, L, mid); } } return 0; }