首页 > 其他 > 详细

【BZOJ3879】SvT(后缀自动机,虚树)

时间:2018-12-27 16:36:48      阅读:131      评论:0      收藏:0      [点我收藏+]

【BZOJ3879】SvT(后缀自动机,虚树)

题面

BZOJ

题解

看着这个东西,询问若干个前缀两两之间的\(lcp\)
显然\(lcp\)就是\(SAM\)构建出来的\(parent\)数上的\(LCA\)所代表的长度。
那么这样子就转为了树型\(dp\)
然后发现是前缀?把串转过来就是后缀了。
\(\sum t\)\(O(n)\)级别的?显然虚树。
那么直接虚树搞搞就好了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAX 1010000
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
int n,m;char ch[MAX];
long long ans;
struct Node
{
    int son[26];
    int len,ff;
}t[MAX];
int last=1,tot=1,lt[MAX];
void extend(int c)
{
    int p=last,np=++tot;last=tot;
    t[np].len=t[p].len+1;
    while(p&&!t[p].son[c])t[p].son[c]=np,p=t[p].ff;
    if(!p)t[np].ff=1;
    else
    {
        int q=t[p].son[c];
        if(t[q].len==t[p].len+1)t[np].ff=q;
        else
        {
            int nq=++tot;
            t[nq]=t[q];t[nq].len=t[p].len+1;
            t[q].ff=t[np].ff=nq;
            while(p&&t[p].son[c]==q)t[p].son[c]=nq,p=t[p].ff;
        }
    }
}
struct Line{int v,next;}e[MAX];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int dfn[MAX],low[MAX],dep[MAX],fa[MAX],tim,size[MAX],hson[MAX],top[MAX];
void dfs1(int u,int ff)
{
    size[u]=1;dep[u]=dep[ff]+1;fa[u]=ff;
    for(int i=h[u];i;i=e[i].next)
    {
        int v=e[i].v;
        dfs1(v,u);size[u]+=size[v];
        if(size[v]>size[hson[u]])hson[u]=v;
    }
}
void dfs2(int u,int tp)
{
    dfn[u]=++tim;top[u]=tp;
    if(hson[u])dfs2(hson[u],tp);
    for(int i=h[u];i;i=e[i].next)
        if(e[i].v!=hson[u])dfs2(e[i].v,e[i].v);
    low[u]=tim;
}
int LCA(int u,int v)
{
    while(top[u]^top[v])(dep[top[u]]<dep[top[v]])?v=fa[top[v]]:u=fa[top[u]];
    return dep[u]<dep[v]?u:v;
}
int p[MAX],S[MAX];
bool vis[MAX];
bool cmp(int a,int b){return dfn[a]<dfn[b];}
int dp(int u)
{
    int ret=0;if(vis[u])ret=1;
    for(int i=h[u];i;i=e[i].next)
    {
        int d=dp(e[i].v);
        ans+=1ll*t[u].len*d*ret;
        ret+=d;
    }
    return ret;
}
int main()
{
    n=read();m=read();
    scanf("%s",ch+1);reverse(&ch[1],&ch[n+1]);
    for(int i=1;i<=n;++i)extend(ch[i]-97),lt[i]=last;
    for(int i=1;i<=tot;++i)if(t[i].ff)Add(t[i].ff,i);
    dfs1(1,0);dfs2(1,1);memset(h,0,sizeof(h));cnt=1;
    while(m--)
    {
        int t=read(),top=0;cnt=0;
        for(int i=1;i<=t;++i)vis[p[i]=lt[n-read()+1]]=true;
        sort(&p[1],&p[t+1],cmp);
        for(int i=t;i>1;--i)p[++t]=LCA(p[i],p[i-1]);
        sort(&p[1],&p[t+1],cmp);t=unique(&p[1],&p[t+1])-p-1;
        for(int i=1;i<=t;++i)
        {
            while(top&&low[S[top]]<dfn[p[i]])--top;
            Add(S[top],p[i]);S[++top]=p[i];
        }
        ans=0;dp(p[1]);printf("%lld\n",ans);
        for(int i=1;i<=t;++i)h[p[i]]=0,vis[p[i]]=false;
    }
    return 0;
}

【BZOJ3879】SvT(后缀自动机,虚树)

原文:https://www.cnblogs.com/cjyyb/p/10185462.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!