表示一个字符串中含有的子串的子序列个数,如时表示子序列的个数,表示子序列的个数,最终答案即为

对一个区间字符串的翻转,对应的变化为区间的对应翻转,即

如果我们快速得到区间对应的,将其翻转,再与区间合并,就能获取每个询问翻转之后的总体答案

考虑合并两段相邻区间的,记为左半部分为右半部分,则有

表示左右部分各自含有的子序列个数加上左右拼起来的个数

用线段树维护即可

#include<cstring>
#include<algorithm>
using namespace std;
template<class T>inline const void read(T &in)
{
    in=0;char ch(getchar());
    while (ch<48||ch>57)ch=getchar();
    while (ch>47&&ch<58)in=(in<<3)+(in<<1)+(ch&15),ch=getchar();
}
typedef long long ll;
constexpr int N(1e5+5);
int n,m;
char s[N];
inline const int trans(const char &c)
{
    switch (c)
    {
        case 'r':return 0;
        case 'e':return 1;
        case 'd':return 2;
        default:return 4;
    }
}
struct Data
{
    ll f[3][3];
    inline Data()
    {
        memset(f,0,sizeof(f));
    }
    inline Data(const int &x)
    {
        memset(f,0,sizeof(f));
        f[x][x]=1;
    }
    inline Data(const char &c)
    {
        const int t(trans(c));
        memset(f,0,sizeof(f));
        f[t][t]=1;
    }
    inline ll *operator[](const int &x){return f[x];}
    inline ll const *operator[](const int &x)const{return f[x];}
    inline friend Data operator+(const Data &a,const Data &b)
    {
        Data c;
        for (int i(0);i<3;i++)
            for (int j(0);j<3;j++)
            {
                c[i][j]=a[i][j]+b[i][j];
                if (i<j)
                    for (int k(i);k<j;k++)
                        c[i][j]+=a[i][k]*b[k+1][j];
                else
                    for (int k(i);k>j;k--)
                        c[i][j]+=a[i][k]*b[k-1][j];
            }
        return c;
    }
    inline const void reverse()
    {
        for (int i(0);i<2;i++)
            for (int j(i+1);j<3;j++)
                swap(f[i][j],f[j][i]);
    }
};
struct Tree
{
    Data val;
    Tree *lson,*rson;
    inline void *operator new(size_t size);
    inline Tree():val(),lson(NULL),rson(NULL){}
    inline const void pushup()
    {
        val=lson->val+rson->val;
    }
    inline Data query(const int &l,const int &r,const int &L,const int &R)
    {
        if (l>=L&&r<=R)return val;
        const int mid(l+r>>1);
        if (R<=mid)return lson->query(l,mid,L,R);
        if (L>mid)return rson->query(mid+1,r,L,R);
        return lson->query(l,mid,L,mid)+rson->query(mid+1,r,mid+1,R);
    }
}*root;
char memoryPool[N*sizeof(Tree)<<1],*tail(memoryPool+sizeof(memoryPool));
inline void *Tree::operator new(size_t size){return tail-=size;}
inline const void build(Tree *&p,const int &l,const int &r)
{
    p=new Tree;
    if (l==r)return p->val=Data(s[l]),void();
    const int mid(l+r>>1);
    build(p->lson,l,mid);
    build(p->rson,mid+1,r);
    p->pushup();
}
int main()
{
    read(n);read(m);
    scanf("%s",s+1);
    build(root,1,n);
    for (int l,r;m--;)
    {
        read(l);read(r);
        if (l>1&&r<n)
        {
            Data f1(root->query(1,n,1,l-1)),f2(root->query(1,n,l,r)),f3(root->query(1,n,r+1,n));
            f2.reverse();
            f1=f1+f2+f3;
            printf("%lld\n",f1[0][2]);
            continue;
        }
        if (l>1)
        {
            Data f1(root->query(1,n,1,l-1)),f2(root->query(1,n,l,n));
            f2.reverse();
            f1=f1+f2;
            printf("%lld\n",f1[0][2]);
            continue;
        }
        if (r<n)
        {
            Data f1(root->query(1,n,1,r)),f2(root->query(1,n,r+1,n));
            f1.reverse();
            f1=f1+f2;
            printf("%lld\n",f1[0][2]);
            continue;
        }
        Data f1(root->val);
        f1.reverse();
        printf("%lld\n",f1[0][2]);
    }
    return 0;
}