为什么要写这个题的题解呢?

因为我觉得很可惜...尽管我做过类似的,类似这题 ,知道是线段树上分治跑dp,但是因为只做过一次,不敢写,因为怕bug然后调不出,事实上我又调了很久,确实菜,但是呢必须得说下次我绝对敢写.

这种题是基于线段树本身带有分治结构,对于每段来说就是先算段内贡献,然后算段外的贡献,假如你学过cdq分治就更好理解了.这是我当初学cdq分治做的视频 .

基于这些,我们令表示线段树管辖区间,连续的子串数量是多少.
然后统计技术即可,和普通线段树相比差别在于,把子树的信息整合到父亲节点.

然后并没有什么难点.

code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5,M=6;
const int mod=998244353;
map<char,int>id={{'F',1},{'e',2},{'i',3},{'M',4},{'a',5}};
char s[N];

struct SegTree{
    int l,r;
    char lazy;
    ll f[M][M];//表示区间l,r i~j的子序列个数.
}Tr[N<<2];

void pushup(int u)
{
    for(int i=1;i<=5;i++)
    {
        for(int j=i;j<=5;j++)
        {
            Tr[u].f[i][j]=(Tr[u<<1].f[i][j]+Tr[u<<1|1].f[i][j])%mod;
            for(int k=i;k<j;k++)
            {
                Tr[u].f[i][j]=(Tr[u].f[i][j]+(Tr[u<<1].f[i][k]*Tr[u<<1|1].f[k+1][j])%mod)%mod;
            }
        }
    }
}

void pushdown(int u)
{
    if(Tr[u].lazy!=0)
    {
        memset(Tr[u<<1].f,0,sizeof Tr[u<<1].f);
        Tr[u<<1].f[id[Tr[u].lazy]][id[Tr[u].lazy]]=(Tr[u<<1].r-Tr[u<<1].l+1);
        Tr[u<<1].lazy=Tr[u].lazy;
        memset(Tr[u<<1|1].f,0,sizeof Tr[u<<1|1].f);
        Tr[u<<1|1].f[id[Tr[u].lazy]][id[Tr[u].lazy]]=(Tr[u<<1|1].r-Tr[u<<1|1].l+1);
        Tr[u<<1|1].lazy=Tr[u].lazy;
        Tr[u].lazy=0;
    }
}

void modify(int u,int l,int r,char c)
{
    if(l>Tr[u].r||r<Tr[u].l)    return;
    if(Tr[u].l>=l&&Tr[u].r<=r)
    {
        memset(Tr[u].f,0,sizeof Tr[u].f);
        Tr[u].lazy=c;
        Tr[u].f[id[c]][id[c]]=(Tr[u].r-Tr[u].l+1);
        return;
    }
    pushdown(u);
    modify(u<<1,l,r,c);
    modify(u<<1|1,l,r,c);
    pushup(u);
}

void build(int u,int l,int r)
{
    Tr[u].l=l,Tr[u].r=r;Tr[u].lazy=0;
    if(l==r)
    {
        memset(Tr[u].f,0,sizeof Tr[u].f);
        Tr[u].f[id[s[l]]][id[s[l]]]=1;
        return;
    }
    int mid=(l+r)>>1;
    build(u<<1,l,mid);
    build(u<<1|1,mid+1,r);
    pushup(u);
}

void run()
{
    int n,q;
    scanf("%d%d",&n,&q);
    scanf("%s",s+1);
    build(1,1,n);
    while(q--)
    {
        int li,ri;
        scanf("%d%d",&li,&ri);
        char op;
        cin>>op;
        modify(1,li,ri,op);
        printf("%lld\n",Tr[1].f[1][5]);
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        run();
    }
    return 0;
}