LOJ#6198. 谢特 SAM+启发式合并+01trie

并不难的一道字符串题.  

显然后缀自动机上进行字典树的启发式合并.  

但是一定注意,题中要求的是两个后缀的 LCP 而不是两个前缀的 LCP. 

所以在构建后缀自动机的时候要从后向前构建.  

刚开始从前向后构建 WA 了半天.  

然后进行启发式合并的时候可以对每个节点维护一个 id[x],如果儿子的大小大于点 $x$ 大小就 swap 一下即可.  

code:   

#include <cstdio>      
#include <vector>
#include <cstring> 
#include <algorithm>   
#define N 200008 
#define ll long long 
#define pb push_back   
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std; 
int ans; 
int last,tot,cnt,n,edges;   
char str[N];    
vector<int>se[N];   
int hd[N],to[N],nex[N];  
int pre[N],mx[N],ch[N][27],id[N],rt[N],val[N];     
struct data { 
    int ch[2],si;  
}s[N*50];    
void add(int u,int v) { 
    nex[++edges]=hd[u];  
    hd[u]=edges,to[edges]=v;   
} 
void ins(int &x,int l,int v) {     
    if(!x) { 
        x=++cnt; 
    }
    if(l==-1) { 
        return;  
    }    
    int d=(v>>l)&1;     
    ins(s[x].ch[d],l-1,v),++s[s[x].ch[d]].si; 
}        
int query(int x,int l,int v) {    
    if(l==-1) {  
        return 0; 
    }         
    int d=1^((v>>l)&1);     
    if(s[x].ch[d]) {  
        return (1<<l)+query(s[x].ch[d],l-1,v);  
    }  
    else { 
        return query(s[x].ch[1^d],l-1,v);  
    }
}
void init() {  
    last=tot=1; 
    for(int i=1;i<N;++i) id[i]=i;   
}     
void extend(int c,int v) {  
    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[q]=pre[np]=nq;  
            for(;p&&ch[p][c]==q;p=pre[p]) ch[p][c]=nq;  
        }
    }
    se[np].pb(v);     
    ins(rt[np],22,val[v]);       
}
void sol(int x) {            
    int y,z; 
    for(int i=hd[x];i;i=nex[i]) {     
        y=to[i],sol(y);    
        if(se[id[x]].size()<se[id[y]].size()) {    
            swap(id[x],id[y]); 
        }   
        for(int j=0;j<se[id[y]].size();++j) {            
            int p=se[id[y]][j];   
            int tmp=mx[x]+query(rt[id[x]],22,val[p]);   
            ins(rt[id[x]],22,val[p]); 
            se[id[x]].pb(p);      
            if(tmp>ans) {   
                ans=tmp; 
            }
        }
    }
}
int main() {  
    // setIO("input"); 
    init();       
    scanf("%d%s",&n,str+1);  
    for(int i=1;i<=n;++i) {
        scanf("%d",&val[i]); 
    }
    for(int i=1;i<=n;++i) { 
        extend(str[n-i+1]-'a',n-i+1);                       
    }   
    for(int i=2;i<=tot;++i) {     
        add(pre[i],i); 
    }    
    sol(1);  
    printf("%d
",ans);   
    return 0; 
}

  

原文地址:https://www.cnblogs.com/guangheli/p/13345988.html