zoukankan      html  css  js  c++  java
  • BZOJ 3879: SvT 虚树 + 后缀自动机

    Description

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

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

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

     Input

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

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

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

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

    Output

    对于每一组询问,输出一行一个整数,表示该组询问的答案.由于答案可能很大,仅需要输出这个答案对于23333333333333333(一个巨大的质数)取模的余数.

    题解:和CF的一个题几乎一模一样,都是利用虚树统计答案

    #include <bits/stdc++.h>
    #define setIO(s) freopen(s".in","r",stdin) , freopen(s".out","w",stdout) 
    #define maxn 1200004 
    #define mod 23333333333333333
    #define ll long long 
    using namespace std;  
    int edges,n,Q; 
    int hd[maxn],to[maxn],nex[maxn],tr[maxn];   
    char str[maxn]; 
    void addedge(int u,int v,int c)                     //1001 个
    { 
        nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; 
    }
    namespace SAM
    {  
        int last, tot; 
        int len[maxn<<1],f[maxn<<1],trans[maxn<<1][27];  
        void init() { last=tot=1; } 
        int extend(int c) 
        {
            int np=++tot,p=last; 
            len[np]=len[p]+1,last=np; 
            while(p&&!trans[p][c]) trans[p][c]=np, p=f[p]; 
            if(!p) f[np]=1; 
            else
            {
                int q=trans[p][c]; 
                if(len[q]==len[p]+1) f[np]=q; 
                else
                {
                    int nq=++tot; 
                    len[nq]=len[p]+1; 
                    memcpy(trans[nq],trans[q],sizeof(trans[q])); 
                    f[nq]=f[q],f[q]=f[np]=nq;    
                    while(p&&trans[p][c]==q) trans[p][c]=nq,p=f[p]; 
                }
            }  
            return np; 
        } 
        void build() 
        {
            for(int i=2;i<=tot;++i) addedge(f[i],i,len[f[i]]-len[i]); 
        }
    }  
    int tim; 
    int dfn[maxn],Top[maxn],hson[maxn],siz[maxn],fa[maxn],dis[maxn];   
    void dfs1(int u,int ff)
    {
        fa[u]=ff,siz[u]=1,dfn[u]=++tim,dis[u]=dis[ff]+1; 
        for(int i=hd[u];i;i=nex[i])
        {
            int v=to[i]; 
            if(v==ff) continue;  
            dfs1(v,u); 
            siz[u]+=siz[v]; 
            if(siz[v]>siz[hson[u]]) hson[u]=v; 
        }
    }
    void dfs2(int u,int tp)
    {
        Top[u]=tp; 
        if(hson[u]) dfs2(hson[u],tp); 
        for(int i=hd[u];i;i=nex[i])
        {
            int v=to[i]; 
            if(v==fa[u]||v==hson[u]) continue; 
            dfs2(v,v); 
        }
    }
    int LCA(int x,int y)
    {
        while(Top[x]!=Top[y]) 
        {
            dis[Top[x]]>dis[Top[y]]?x=fa[Top[x]]:y=fa[Top[y]]; 
        }
        return dis[x]<dis[y]?x:y; 
    } 
    vector<int>G[maxn<<1]; 
    ll ans=0; 
    int t=0; 
    int A[maxn<<1],mk[maxn<<1],size[maxn<<1],S[maxn<<1];         
    bool cmp(int i,int j) 
    {
        return dfn[i]<dfn[j]; 
    }
    void addvir(int x,int y)
    {  
        G[x].push_back(y); 
    }
    void insert(int x)
    {
        if(t<=1) { S[++t]=x; return; }
        int lca=LCA(S[t],x); 
        if(lca==S[t]) { S[++t]=x; return; } 
        while(t>1&&dis[S[t-1]]>=dis[lca]) addvir(S[t-1],S[t]),--t; 
        if(S[t]!=lca) addvir(lca,S[t]),S[t]=lca; 
        S[++t]=x;   
    } 
    void DP(int x) 
    { 
        size[x]=mk[x]; 
        for(int i=0;i<G[x].size();++i) 
        {
            DP(G[x][i]); 
            ans+=1ll*size[x]*size[G[x][i]]%mod*SAM::len[x]%mod;  
            ans%=mod; 
            size[x]+=size[G[x][i]]; 
        }
        G[x].clear(); 
        mk[x]=0; 
    } 
    void work() 
    { 
        int k,a; 
        scanf("%d",&k); 
        for(int i=1;i<=k;++i) scanf("%d",&a), A[i]=tr[a], mk[A[i]]=1;           
        sort(A+1,A+1+k,cmp);            
        k=unique(A+1,A+1+k)-(A+1);         
        t=ans=0;    
        if(A[1]!=1) S[++t]=1;                            
        for(int i=1;i<=k;++i) insert(A[i]);   
        while(t>1) addvir(S[t-1],S[t]),--t;     
        DP(1);     
        printf("%lld
    ",ans);    
    }
    int main() 
    {
        // setIO("input");   
        scanf("%d%d%s",&n,&Q,str+1); 
        SAM::init();      
        for(int i=n;i>=1;--i) tr[i]=SAM::extend(str[i]-'a');    
        SAM::build();      
        dis[1]=1,dfs1(1,0),dfs2(1,1);        
        for(int i=1;i<=Q;++i) 
        {  
            work();   
        }
        return 0; 
    }
    

      

  • 相关阅读:
    centos6下安装部署hadoop2.2
    centos 卸载自带的 java
    完全分布式Hadoop2.3安装与配置
    hadoop安装与WordCount例子
    CentOS 6.5 下载地址
    碎片化
    DRM加密技术是怎么一回事
    DRM你又赢了:其API纳入HTML5标准
    java 对视频和图片进行加密解密
    HadoopDB:混合分布式系统
  • 原文地址:https://www.cnblogs.com/guangheli/p/11133043.html
Copyright © 2011-2022 走看看