传送门

$SvT=SAM+Vitual\ Tree$?(猜的)

其实是比较套路的$SAM$+虚树。把串反过来建$SAM$,找出每个后缀对应的节点,求在$parent\ tree$上两两$LCA$的$len$和。

在$parent\ tree$上造虚树,统计一下每个点子树中有多少个关键点记为$siz$。

考虑每个节点的贡献,它所有儿子两两之间会有$siz$之积的点数$LCA$是它,随便加一加乘一乘就好了。

(胡言乱语.jpg)

下面由我来展示一波高端错误:

建虚树时对$dfs$序排序,用的比较函数:

    inline bool cmp(int x,int y){return origin::seg[x]<origin::seg[y]?x:y;}

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>

#define maxn 1000005
#define inf 0x3f3f3f3f

const long long mod = 23333333333333333ll;

using namespace std;

inline int read(){
    int x=0,y=0;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return y?-x:x;
}
int n,m;
namespace Suffix_Automaton{
#define son(x,y) son[x][y]
    char s[maxn];
    int w[maxn],len[maxn],fa[maxn],son[maxn][26],last=1,cnt=1;
    void insert(int c){
        int p=last,ne=last=++cnt;
        len[ne]=len[p]+1;
        while(p&&!son(p,c))son(p,c)=ne,p=fa[p];
        if(!p)fa[ne]=1;
        else {
            int q=son(p,c);
            if(len[q]==len[p]+1)fa[ne]=q;
            else {
                int sp=++cnt;
                memcpy(son[sp],son[q],sizeof son[q]);
                len[sp]=len[p]+1,fa[sp]=fa[q],fa[q]=fa[ne]=sp;
                while(p&&son(p,c)==q)son(p,c)=sp,p=fa[p];
            }
        }
    }
    void init(){
        scanf("%s",s+1);
        for(register int i=n;i;--i)insert(s[i]-'a');
        w[0]=1;
        for(register int i=1;i<=n;++i)w[i]=son(w[i-1],s[n-i+1]-'a');
        for(register int i=1;i<=n>>1;++i)swap(w[i],w[n-i+1]);
    }
}
namespace origin{
    int seg[maxn],top[maxn],son[maxn],siz[maxn],deep[maxn],fa[maxn],h[maxn],num,all;
    struct edge{
        int pre,to;
    }e[maxn];
    inline void add(int from,int to){
        e[++num].pre=h[from],h[from]=num,e[num].to=to;
    }
    void dfs1(int node=1){
        siz[node]=1;
        int x;
        for(register int i=h[node];i;i=e[i].pre){
            x=e[i].to;
            deep[x]=deep[node]+1,fa[x]=node,dfs1(x);
            siz[node]+=siz[x];
            if(siz[x]>siz[son[node]])son[node]=x;
        }
    }
    void dfs2(int node=1){
        seg[node]=++all;
        if(son[node]){
            top[son[node]]=top[node],dfs2(son[node]);
            int x;
            for(register int i=h[node];i;i=e[i].pre){
                x=e[i].to;
                if(x!=son[node])top[x]=x,dfs2(x);
            }
        }
    }
    int lca(int x,int y){
        while(top[x]!=top[y])deep[top[x]]<deep[top[y]]?y=fa[top[y]]:x=fa[top[x]];
        return deep[x]<deep[y]?x:y;
    }
}
namespace virt{
    long long ans;
    int siz[maxn],h[maxn],num;
    vector<int>p;
    bool vis[maxn];
    struct edge{
        int pre,to;
    }e[maxn];
    inline void add(int from,int to){
        if(origin::seg[from]>origin::seg[to])swap(from,to);
        e[++num].pre=h[from],h[from]=num,e[num].to=to;
    }
    inline bool cmp(int x,int y){return origin::seg[x]<origin::seg[y];}
    struct Monostack{
        int sta[maxn],top;
        void push(int x){sta[++top]=x;}
        void clear(){
            for(register int i=2;i<=top;++i)add(sta[i-1],sta[i]);
            top=0;
        }
        void check(int x){
            int l=origin::lca(x,sta[top]);
            h[x]=0;
            if(l!=sta[top]){
                while(origin::seg[l]<origin::seg[sta[top-1]])add(sta[top-1],sta[top]),--top;
                --top;
                if(l!=sta[top])h[l]=0,add(sta[top+1],l),push(l);
                else add(sta[top+1],l);
            }
            push(x);
        }
    }s;
    void build(){
        h[1]=0,s.push(1);
        for(vector<int>::iterator iter=p.begin();iter!=p.end();++iter)s.check(*iter);
        s.clear();
    }
    void dfs(int node=1){
        siz[node]=vis[node];
        int x;
        long long k=0;
        for(register int i=h[node];i;i=e[i].pre){
            x=e[i].to;
            dfs(x),k+=1ll*siz[x]*siz[node],siz[node]+=siz[x];
            if(k>=mod)k%=mod;
        }
        ans+=k*Suffix_Automaton::len[node];    
        if(ans>=mod)ans%=mod;
    }
    void solve(){
        ans=num=0,p.clear();
        int t=read(),x;
        while(t--){
            if(vis[x=Suffix_Automaton::w[read()]])continue;
            p.push_back(x),vis[x]=1;
        }
        sort(p.begin(),p.end(),cmp);
        build(),dfs();
        for(vector<int>::iterator iter=p.begin();iter!=p.end();++iter)vis[*iter]=0;
        printf("%lld\n",ans);

    }
}
int main(){
    n=read(),m=read();
    Suffix_Automaton::init();
    for(register int i=2;i<=Suffix_Automaton::cnt;++i)origin::add(Suffix_Automaton::fa[i],i);
    origin::dfs1(),origin::dfs2();
    while(m--)virt::solve();
}