• 洛谷P5115 Check,Check,Check one two! 边分治+虚树+SAM


    绝对是我写过最长的一份代码了.   

    这个快敲吐了. 

    通过这道题能 get 到一个套路:

    两颗树同时统计信息的题可以考虑在个树上跑边分治,把点扔到另一颗树的虚树上,然后跑虚树DP.

    具体地,这道题中我们发现 $LCP$ 长度是反串后缀树 $LCA$ 深度,$LCS$ 是正串后缀树 $LCA$ 深度.

    我们建出正反两串后缀树后,将长度大于 K1/K2 的点的深度置为 0,然后跑一个边分+虚树即可.

    code: 

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <string>
    #include <vector>
    #include <map>      
    #define N 200007
    #define inf 0x3f3f3f3f 
    #define ull unsigned long long
      
    // 代码已写完,人已阵亡.
          
    using namespace std;
      
    int bug;  
    int K1,K2;
    ull ans,W;
    char S[N];   
      
    namespace IO { 
      
        void setIO(string s)
        {
            string in=s+".in";
            string out=s+".out";
            freopen(in.c_str(),"r",stdin);
            // freopen(out.c_str(),"w",stdout);
        }
      
    };
      
    struct SAM {      
      
        #define M N<<1 
      
        int tot,last;   
        struct Edge { 
            int to,w;
            Edge(int to=0,int w=0):to(to),w(w){}  
        }; 
        vector<Edge>G[M];
        int pre[M],ch[M][26],mx[M],str_sam[M],sam_str[M],depth[M];             
      
        void Initialize() { tot=last=1; }   
      
        void extend(int c)
        {       
            int np=++tot,p=last; 
            mx[np]=mx[p]+1,last=np;
            for(;p&&!ch[p][c];p=pre[p]) ch[p][c]=np; 
            if(!p) pre[np]=1;
            else
            {
                int q=ch[p][c];
                if(mx[q]==mx[p]+1) pre[np]=q;
                else
                {
                    int nq=++tot;   
                    mx[nq]=mx[p]+1;  
                    memcpy(ch[nq],ch[q],sizeof(ch[q]));  
                    pre[nq]=pre[q],pre[np]=pre[q]=nq;  
                    for(;p&&ch[p][c]==q;p=pre[p])  ch[p][c]=nq;
                }
            }    
        }
          
      
        void Build_LCP()
        {     
            int n=strlen(S+1),i,j,p=1;
            for(i=1;i<=n;++i)
            {
                p=ch[p][S[n-i+1]-'a']; 
                sam_str[p]=n-i+1;
                str_sam[n-i+1]=p;                   
            }
            for(i=2;i<=tot;++i)
            {
                if(mx[i]>K1) depth[i]=0;         
                else depth[i]=mx[i]; 
            }
            for(i=2;i<=tot;++i)  G[pre[i]].push_back(Edge(i,depth[i]-depth[pre[i]]));       
        } 
          
        void Build_LCS()
        {
            int n=strlen(S+1),i,j,p=1; 
            for(i=1;i<=n;++i)
            {
                p=ch[p][S[i]-'a']; 
                sam_str[p]=i;
                str_sam[i]=p; 
            }  
            for(i=2;i<=tot;++i)
            {
                if(mx[i]>K2) depth[i]=0;
                else  depth[i]=mx[i];
            }
            for(i=2;i<=tot;++i)  G[pre[i]].push_back(Edge(i,depth[i]-depth[pre[i]]));   
        }   
      
        #undef M
      
    }lcp,lcs;
      
    namespace vir {    
      
        vector<int>G[N<<2];
        vector<int>clr;  
    
        int t,sta,tot;
        int is1[N<<2],is2[N<<2];
        int dfn[N<<2],dep[N<<2],size[N<<2],son[N<<2],top[N<<2],f[N<<2];     
        int S[N<<2],val[N<<2],re[N<<2];
        ull size1[N<<2],size2[N<<2];   
        ull sum1[N<<2],sum2[N<<2];        
      
        bool cmp(int a,int b)
        {
            return dfn[a]<dfn[b]; 
        }
      
        void get_dfn(int x,int fa)
        {       
            dfn[x]=++t;         
            size[x]=1;
            f[x]=fa; 
            for(int i=0;i<lcp.G[x].size();++i)
            {
                int y=lcp.G[x][i].to; 
                if(y==fa) continue;
                dep[y]=dep[x]+1;  
                get_dfn(y,x);     
                size[x]+=size[y];
                if(size[y]>size[son[x]]) son[x]=y;
            }      
        } 
      
        void dfs2(int u,int tp)
        {
            top[u]=tp;
            if(son[u]) dfs2(son[u],tp);
            for(int i=0;i<lcp.G[u].size();++i)
            {
                int v=lcp.G[u][i].to;  
                if(v==son[u]||v==f[u]) continue;   
                dfs2(v,v);  
            }
        }
      
        int LCA(int x,int y)
        {
            while(top[x]!=top[y])
            {
                dep[top[x]]>dep[top[y]]?x=f[top[x]]:y=f[top[y]];
            }
            return dep[x]<dep[y]?x:y;
        }
      
        void _new(int x,int v,int c)
        {
            ++tot;
            re[tot]=x;
            val[x]=v;
            if(c==1) is1[x]=1;
            else is2[x]=1;
        }  
      
        void addvir(int x,int y)
        { 
            G[x].push_back(y);
        }
      
        void Initialize()
        {
            t=0; 
            get_dfn(1,0); 
            dfs2(1,1);          
        }     
      
        void Insert(int x)
        {
            if(sta<=1)
            {
                S[++sta]=x;    
                return;
            }
            int lca=LCA(S[sta],x);     
            if(lca==S[sta]) S[++sta]=x;
            else
            {
                while(sta>1&&dep[S[sta-1]]>=dep[lca]) addvir(S[sta-1],S[sta]),--sta;  
                if(S[sta]==lca)  S[++sta]=x;                         
                else
                {
                    addvir(lca,S[sta]); 
                    S[sta]=lca;
                    S[++sta]=x; 
                } 
            }
        }
      
        void Build()
        {  
            sta=0;
            sort(re+1,re+1+tot,cmp);                         
            if(re[1]!=1) S[++sta]=1;         
            for(int i=1;i<=tot;++i) Insert(re[i]);
            while(sta>1)  addvir(S[sta-1],S[sta]),--sta;                       
        }  
      
        void DP(int x)
        {   
            clr.push_back(x); 
            for(int i=0;i<G[x].size();++i)
            {
                int y=G[x][i];
                DP(y);          
                size1[x]+=size1[y];
                size2[x]+=size2[y]; 
                sum1[x]+=sum1[y]; 
                sum2[x]+=sum2[y];             
            }
            ull tmp=0; 
            ull cntw=0;
            ull cur=0; 
            for(int i=0;i<G[x].size();++i)
            { 
                int y=G[x][i];   
                tmp+=(sum1[x]-sum1[y])*size2[y];      
                tmp+=(sum2[x]-sum2[y])*size1[y];            
                cntw+=(size1[x]-size1[y])*size2[y];
            }  
            cur+=tmp*lcp.depth[x];         
            cur-=cntw*W*lcp.depth[x]; 
            if(is1[x])
            {  
                cur+=size2[x]*val[x]*lcp.depth[x];  
                cur+=sum2[x]*lcp.depth[x];  
                cur-=size2[x]*W*lcp.depth[x]; 
            } 
            if(is2[x])
            {
                cur+=size1[x]*val[x]*lcp.depth[x]; 
                cur+=sum1[x]*lcp.depth[x];  
                cur-=size1[x]*W*lcp.depth[x]; 
            }     
            ans+=cur/2;  
            size1[x]+=is1[x];
            size2[x]+=is2[x]; 
            sum1[x]+=is1[x]*val[x];
            sum2[x]+=is2[x]*val[x]; 
            G[x].clear();       
        }
      
        void solve()
        {
            Build(); 
            DP(1); 
            for(int i=0;i<clr.size();++i) 
            {
                int x=clr[i];   
                val[x]=sum1[x]=sum2[x]=size1[x]=size2[x]=is1[x]=is2[x]=0;    
            }           
            for(int i=1;i<=tot;++i)
            {         
                re[i]=0; 
            }
            tot=0; 
            sta=0;      
            clr.clear(); 
        }
    };  // 虚树
      
    int tot,edges=1;
    int totsize,rt1,rt2,mx,ed,lsc,rsc;
    int hd[N<<2],vis[N<<3],size[N<<2];
      
    struct Edge {
        int to,w,nex; 
    }e[N<<3];  
       
    struct Node { 
        int u,dis,val;      
        Node(int u=0,int dis=0,int val=0):u(u),dis(dis),val(val){}         
    }L[N<<2],R[N<<2];
      
    void add_div(int x,int y,int z)
    {
        e[++edges].nex=hd[x],hd[x]=edges,e[edges].to=y,e[edges].w=z; 
    }  
      
    void Build_Tree(int x,int fa)
    {
        int ff=0;             
        for(int i=0;i<lcs.G[x].size();++i)
        {
            int y=lcs.G[x][i].to; 
            if(y==fa)  continue;  
            if(!ff)
            {
                ff=x;  
                add_div(ff,y,lcs.G[x][i].w);
                add_div(y,ff,lcs.G[x][i].w);  
            }
            else
            {
                ++tot;        
                add_div(ff,tot,0);
                add_div(tot,ff,0);                         
                add_div(tot,y,lcs.G[x][i].w); 
                add_div(y,tot,lcs.G[x][i].w); 
                ff=tot;        
            }
            Build_Tree(y,x); 
        }
    }
      
    void find_edge(int x,int fa)
    {  
        size[x]=1;
        for(int i=hd[x];i;i=e[i].nex)
        {
            int y=e[i].to; 
            if(y==fa||vis[i])  continue;  
            find_edge(y,x);
            int now=max(size[y],totsize-size[y]);  
            if(now<mx)
            {
                mx=now;
                ed=i; 
                rt1=y; 
                rt2=x;  
            }
            size[x]+=size[y];
        }
    }
      
      
    void get_node(int x,int fa,int dep,int ty)
    {     
        if(ty==1)
        {           
            if(lcs.sam_str[x])  L[++lsc]=Node(lcs.sam_str[x],lcs.depth[x]-dep,dep); 
        }
        else
        {  
            if(lcs.sam_str[x])  R[++rsc]=Node(lcs.sam_str[x],lcs.depth[x]-dep,dep);
        }
        for(int i=hd[x];i;i=e[i].nex)
        {
            int y=e[i].to;   
            if(vis[i]||y==fa)  continue;  
            get_node(y,x,dep+e[i].w,ty); 
        }
    } 
    
    void Divide_And_conquer(int x)
    {      
        if(totsize==1) return; 
        mx=inf;  
        rt1=rt2=ed=0;     
        find_edge(x,0);             
        vis[ed]=vis[ed^1]=1;    
        lsc=rsc=0;                                      
        get_node(rt1,0,0,1); 
        get_node(rt2,0,0,2);            
        W=(ull)e[ed].w;  
        ull tmp=ans;   
      
        for(int i=1;i<=lsc;++i) vir::_new(lcp.str_sam[L[i].u],L[i].dis,1); 
        for(int i=1;i<=rsc;++i) vir::_new(lcp.str_sam[R[i].u],R[i].dis,2); 
        vir::solve();                    
    
        int tmprt1=rt1,tmprt2=rt2;           
        int sizert1=size[rt1],sizert2=totsize-size[rt1];           
        totsize=sizert1;      
        Divide_And_conquer(tmprt1);    
        totsize=sizert2; 
        Divide_And_conquer(tmprt2); 
    }
      
    int main()
    {
        // IO::setIO("input");
        int i,j,n; 
        scanf("%s%d%d",S+1,&K1,&K2);        
        n=strlen(S+1);    
        lcp.Initialize(); 
        lcs.Initialize(); 
        for(i=1;i<=n;++i)
        {    
            lcs.extend(S[i]-'a'); 
            lcp.extend(S[n-i+1]-'a'); 
        }
        lcs.Build_LCS(); 
        lcp.Build_LCP();
        tot=lcs.tot;     
        Build_Tree(1,0); 
        vir::Initialize();    
        totsize=tot;
        Divide_And_conquer(1);
        printf("%llu
    ",ans); 
        return 0;
    }
    

      

  • 相关阅读:
    NSArray的枚举使用方法
    NSArray的创建(一)
    关于Description的一些理解
    NSString的形式--可变字符串--改方法Alter
    iOS音频流播放、后台播放、远程控制、锁屏封面等总结
    10个重要的算法C语言实现源代码
    OC方法积累
    UIDevice获取设备数据以及如何获取应用信息
    iOS如何取得APP的版本信息跟Apple服务器对比进行升级提示?
    新浪微博-开发过程
  • 原文地址:https://www.cnblogs.com/guangheli/p/12107723.html
Copyright © 2020-2023  润新知