ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

(我并不想告诉你题目名字是什么鬼)

有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n].

现在有若干组询问,对于每一个询问,我们给出若干个后缀(以其在S中出现的起始位置来表示),求这些后缀两两之间的LCP(LongestCommonPrefix)的长度之和.一对后缀之间的LCP长度仅统计一遍.

Input

第一行两个正整数n,m,分别表示S的长度以及询问的次数.

接下来一行有一个字符串S.

接下来有m组询问,对于每一组询问,均按照以下格式在一行内给出:

首先是一个整数t,表示共有多少个后缀.接下来t个整数分别表示t个后缀在字符串S中的出现位置.

Output

对于每一组询问,输出一行一个整数,表示该组询问的答案.由于答案可能很大,仅需要输出这个答案对于23333333333333333(一个巨大的质数)取模的余数.
建出后缀树,询问相当于后缀树上一些点间两两的lca的深度之和,建出虚树然后树形dp求解
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef long long i64;
const int N=1e6+7;
char s[N];
int nx[N][26],l[N],fa[N],pp=1,pv=1;
int n,m,pos[N];
int e0[N],es[N],enx[N],ep=2,sz[N],son[N],dep[N],top[N],id[N][2],idp=0,ss[N],sp=0;
int ed[N],tk=0;
char buf[50000000],*ptr=buf-1;
int _(){
    int x=0;
    while(*ptr<48)++ptr;
    while(*ptr>47)x=x*10+*ptr++-48;
    return x;
}
void _(char*s){
    while(*ptr<33)++ptr;
    while(*ptr>32)*s++=*ptr++;
    *ptr=0;
}
int ins(int x){
    int p=pv,np=++pp;
    l[np]=l[p]+1;
    while(p&&!nx[p][x])nx[p][x]=np,p=fa[p];
    if(!p)fa[np]=1;
    else{
        int q=nx[p][x];
        if(l[q]==l[p]+1)fa[np]=q;
        else{
            int nq=++pp;
            l[nq]=l[p]+1;
            memcpy(nx[nq],nx[q],sizeof(nx[0]));
            fa[nq]=fa[q];
            fa[q]=fa[np]=nq;
            while(p&&nx[p][x]==q)nx[p][x]=nq,p=fa[p];
        }
    }
    return pv=np;
}
void push(int w){
    ss[++sp]=w;
    id[w][0]=++idp;
    dep[w]=dep[fa[w]]+1;
}
void hld_pre(){
    for(int i=1;i<=pp;++i){
        es[ep]=i;enx[ep]=e0[fa[i]];e0[fa[i]]=ep++;
        sz[i]=1;
    }
    push(1);
    while(sp){
        int w=ss[sp],&e=e0[w];
        if(!e){
            int f=fa[w];
            sz[f]+=sz[w];
            if(w[sz]>f[son][sz])f[son]=w;
            id[w][1]=idp;
            --sp;
            continue;
        }
        int u=es[e];
        e=enx[e];
        push(u);
    }
    for(int i=1;i<=pp;++i)if(i[fa][son]!=i){
        for(int w=i;w;w=w[son])w[top]=i;
    }
}
int lca(int x,int y){
    int a=top[x],b=top[y];
    while(a!=b){
        if(dep[a]>dep[b])x=fa[a],a=top[x];
        else y=fa[b],b=top[y];
    }
    return dep[x]<dep[y]?x:y;
}
bool cmp(int a,int b){
    return id[a][0]<id[b][0];
}
int cs[N],cp,tp[N],_f[N];
void cal(){
    i64 ans=0;
    int p=0;
    _f[ss[++sp]=cs[p++]]=0;
    while(sp){
        int w=ss[sp];
        if(p<cp&&id[cs[p]][0]<=id[w][1])_f[ss[++sp]=cs[p++]]=w;
        else{
            --sp;
            int f=_f[w];
            if(f>1){
                ans+=i64(l[f])*tp[f]*tp[w];
                tp[f]+=tp[w];
            }
        }
    }
    printf("%lld\n",ans);
}
int main(){
    fread(buf,1,sizeof(buf),stdin)[buf]=0;
    n=_();m=_();
    _(s+1);
    for(int i=n;i;--i)pos[i]=ins(s[i]-'a');
    hld_pre();
    for(int c;m;--m){
        c=_();
        cp=0;
        ++tk;
        for(int i=0,x;i<c;++i){
            x=pos[_()];
            if(ed[x]!=tk)ed[cs[cp++]=x]=tk,tp[x]=1;
        }
        std::sort(cs,cs+cp,cmp);
        c=cp;
        for(int i=0,pv=1;i<c;++i){
            int x=lca(cs[i],pv);
            pv=cs[i];
            if(ed[x]!=tk)ed[cs[cp++]=x]=tk,tp[x]=0;
        }
        std::sort(cs,cs+cp,cmp);
        cal();
    }
    return 0;
}

 

posted on 2017-06-14 15:56  nul  阅读(250)  评论(0编辑  收藏  举报