// // main.cpp // codeforces // // Created by Yi Xu on 11/24/16. // Copyright © 2016 Yi Xu. All rights reserved. // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; #define XINF INT_MAX #define INF 0x3FFFFFFF #define mp(X,Y) make_pair(X,Y) #define pb(X) push_back(X) #define rep(X,N) for(int X=0;X=L;X--) #define clr(A,X) memset(A,X,sizeof(A)) #define IT iterator #define ALL(X) (X).begin(),(X).end() #define PQ std::priority_queue typedef long long ll; typedef unsigned long long ull; typedef pair PII; typedef vector VII; typedef vector VI; string str; int a[100010]; int cnt[700010][26]; int ch[700010]; int tmp[26]; int dp[26]; int ji[26],ou[26]; const ll MOD = 1000000007; ll mypow(ll n,int m){ ll ret = 1LL; while(m){ if(m & 1)ret = ret * n % MOD; n = n * n % MOD; m >>= 1; } return ret; } void push_up(int cur){ for(int i = 0 ;i < 26; i ++){ cnt[cur][i] = cnt[cur << 1][i] + cnt[cur << 1 | 1][i]; } } void build(int l,int r,int cur){ if(l > r)return; //cout << l << " " << r << " " << cur << endl; if(l == r){ cnt[cur][a[l]] = 1; return; } int mid = (l + r) >> 1; build(l,mid,cur << 1); build(mid + 1,r,cur << 1 | 1); push_up(cur); } void push_down(int cur){ for(int i = 0 ; i < 26; i ++){ tmp[( i + ch[cur]) % 26] = cnt[cur][i]; } rep(i,26){ cnt[cur][i] = tmp[i]; } ch[cur << 1] = ch[cur << 1 | 1] = ch[cur]; ch[cur] = 0; } void query(int l,int r,int lx,int rx,int cur){ if(l > r)return; if(l > rx || r < lx)return; //cout << l << " " << r << " " << cur << endl; if(ch[cur])push_down(cur); if(l >= lx && r <= rx){ rep(i,26){ dp[i] += cnt[cur][i]; } return; } int mid = (l + r ) >> 1; query(l,mid,lx,rx,cur << 1); query(mid + 1, r, lx ,rx, cur << 1 | 1); } void update(int l,int r,int lx,int rx,int cur, int inc){ if(l > r)return; if(l > rx || r < lx)return; if(l >= lx && r <= rx){ ch[cur] += inc; while(ch[cur] >= 26)ch[cur] -= 26; push_down(cur); return; } int mid = (l + r ) >> 1; update(l,mid,lx,rx,cur << 1,inc); update(mid + 1, r, lx ,rx, cur << 1 | 1,inc); push_up(cur); } int main() { ios::sync_with_stdio(0); int n,q; cin >> n >> q; cin >> str; rep(i,n){ a[i] = str[i] - 'a'; } build(0, n - 1, 1); //cout << "ok" << endl; while(q--){ int op,x,y,z; cin >> op >> x >> y; if(n < 500){ if(op == 1){ cin >> z; z %= 26; for(int i = x; i <= y ; i ++){ a[i] = (a[i] + z) % 26; } }else{ memset(dp,0,sizeof(dp)); for(int i = x ; i <= y ; i ++){ dp[a[i]]++ ; } ll ans = -1; rep(i,26){ if(dp[i]){ ji[i] = ou[i] = mypow(2, dp[i] - 1); }else{ ji[i] = 0; ou[i] = 1; } } ll gao0 = 1; rep(i,26){ ll gao1 = 1; rep(j,26){ if(i == j){ gao1 = gao1 * ji[j] % MOD; }else{ gao1 = gao1 * ou[j] % MOD; } } ans += gao1; gao0 = gao0 * ou[i] % MOD; } ans += gao0 + MOD; ans %= MOD; //rep(i,26)cout << dp[i] << " "; //cout << endl; cout << ans << endl; } continue; } if(op == 1){ cin >> z; z %= 26; update(0, n - 1, x, y , 1, z); }else{ memset(dp, 0, sizeof(dp)); query(0, n-1, x, y, 1); ll ans = -1; rep(i,26){ if(dp[i]){ ji[i] = ou[i] = mypow(2, dp[i] - 1); }else{ ji[i] = 0; ou[i] = 1; } } ll gao0 = 1; rep(i,26){ ll gao1 = 1; rep(j,26){ if(i == j){ gao1 = gao1 * ji[j] % MOD; }else{ gao1 = gao1 * ou[j] % MOD; } } ans += gao1; gao0 = gao0 * ou[i] % MOD; } ans += gao0 + MOD; ans %= MOD; //rep(i,26)cout << dp[i] << " "; //cout << endl; cout << ans << endl; } } return 0; }