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


    【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
    ",ans);
    		for(int i=1;i<=t;++i)h[p[i]]=0,vis[p[i]]=false;
    	}
    	return 0;
    }
    
  • 相关阅读:
    Mybatis 传入的参数为List
    IDEA 自动清除不使用的 引用包
    java List去除重复数据
    oracle 导出数据库报错 EXP-00002: 写入导出文件时出错 EXP-00000: 导出终止失败
    Tomcat修改窗口名
    Oracle忘记密码找回
    3springboot执行原理及自动装配原理
    2springboot第一个程序
    springboot项目有红叉,但是没有运行没有报错。
    1springboot与微服务
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10185462.html
Copyright © 2020-2023  润新知