#include #define LOCAL 0 #define lli long long int #define llu unsigned long long int #define ld long double #define all(v) v.begin(),v.end() #define pb push_back #define mp make_pair #define F first #define S second #define si(n) scanf("%d",&n) #define slli(n) scanf("%lld",&n); #define ss(n) scanf("%s",n); const long double EPS = 1e-10; const lli MOD = 1000000007ll; const lli mod1 = 1000000009ll; const lli mod2 = 1100000009ll; int INF = (int)1e9; lli INFINF = (lli)1e18; int debug = 0; long double PI = acos(-1.0); using namespace std; lli bit_count(lli _x){lli _ret=0;while(_x){if(_x%2==1)_ret++;_x/=2;}return _ret;} lli bit(lli _mask,lli _i){return (_mask&(1<<_i))==0?0:1;} lli powermod(lli _a,lli _b,lli _m=MOD){lli _r=1;while(_b){if(_b%2==1)_r=(_r*_a)%_m;_b/=2;_a=(_a*_a)%_m;}return _r;} lli add(lli a,lli b,lli m=MOD){lli x=a+b;while(x>=m)x-=m;while(x<0)x+=m;return x;} lli sub(lli a,lli b,lli m=MOD){lli x=a-b;while(x<0)x+=m;while(x>=m)x-=m;return x;} lli mul(lli a,lli b,lli m=MOD){lli x=a*1ll*b;x%=m;if(x<0)x+=m;return x;} struct Node{ int cnt[26]; int lazy; }; namespace Segtree{ typedef int stt; const int MAXN = 100010; struct Node Segtree[4*MAXN]; Node MergeSegTree(Node a,Node b){ struct Node temp; temp.lazy = 0; for(int i=0;i<26;i++) temp.cnt[i] = a.cnt[i]+b.cnt[i]; return temp; } void lazyupd(int s,int e,int idx){ if(s>e || Segtree[idx].lazy == 0) return; int t = Segtree[idx].lazy; int temp[26]={0}; for(int i=0;i<26;i++) temp[i] = Segtree[idx].cnt[i]; for(int i=0;i<26;i++) Segtree[idx].cnt[i] = temp[sub(i,t,26)]; if(s != e){ Segtree[2*idx+1].lazy = add(Segtree[2*idx+1].lazy,t,26); Segtree[2*idx+2].lazy = add(Segtree[2*idx+2].lazy,t,26); } Segtree[idx].lazy = 0; } void BuildSegTree(string &str,int s,int e,int idx){ if(s==e){ for(int i=0;i<=26;i++) Segtree[idx].cnt[i] = 0; Segtree[idx].cnt[str[s]-'a']++; Segtree[idx].lazy = 0; } else{ int mid = (s+e)>>1; BuildSegTree(str,s,mid,2*idx+1); BuildSegTree(str,mid+1,e,2*idx+2); Segtree[idx] = MergeSegTree(Segtree[2*idx+1],Segtree[2*idx+2]); } } void UpdateSegTree(int s,int e,int x,int y,stt t,int idx){ if(s==x && e==y){ Segtree[idx].lazy = add(Segtree[idx].lazy,t,26); lazyupd(s,e,idx); return; } lazyupd(s,e,idx); lli mid = (s+e)>>1; if(y<=mid){ UpdateSegTree(s,mid,x,y,t,2*idx+1); lazyupd(mid+1,e,2*idx+2); } else if(x>mid){ UpdateSegTree(mid+1,e,x,y,t,2*idx+2); lazyupd(s,mid,2*idx+1); } else{ UpdateSegTree(s,mid,x,mid,t,2*idx+1); UpdateSegTree(mid+1,e,mid+1,y,t,2*idx+2); } Segtree[idx] = MergeSegTree(Segtree[2*idx+1],Segtree[2*idx+2]); } Node QuerySegTree(int s,int e,int x,int y,int idx){ lazyupd(s,e,idx); if(s==x && e==y) return Segtree[idx]; int mid = (s+e)>>1; if(y<=mid) return QuerySegTree(s,mid,x,y,2*idx+1); if(x>mid) return QuerySegTree(mid+1,e,x,y,2*idx+2); return MergeSegTree(QuerySegTree(s,mid,x,mid,2*idx+1),QuerySegTree(mid+1,e,mid+1,y,2*idx+2)); } } int N,Q; string s; char tempsss[100010]; lli sum[100010]; int main() { if(LOCAL){ freopen("input.txt","r",stdin); //freopen("output.txt","w",stdout); debug = 1; } srand (time(NULL)); sum[1] = 1; for(int i=2;i<=100000;i++){ sum[i] = mul(sum[i-1],i); sum[i] = add(sum[i],i); } si(N);si(Q); ss(tempsss); s = tempsss; s = ' ' + s; Segtree::BuildSegTree(s,1,N,0); for(int i=1;i<=Q;i++){ int type,x,y; si(type);si(x);si(y); x++;y++; if(type == 1){ int t; si(t); Segtree::UpdateSegTree(1,N,x,y,t%26,0); } else{ Node ret = Segtree::QuerySegTree(1,N,x,y,0); lli ans = 0; int tot = 0; int vali = 0; for(int i=0;i<26;i++){ if(ret.cnt[i]<2) continue; tot += ret.cnt[i]-1; } if(tot > 0){ lli temp = powermod(2,tot); temp = sub(temp,1); ans = add(ans,temp); } vali = tot = 0; for(int i=0;i<26;i++){ if(ret.cnt[i]<1) continue; tot += ret.cnt[i]-1; vali ++; } if(tot >= 0){ lli temp = powermod(2,tot); temp = mul(temp,vali); ans = add(ans,temp); } cout<