BZOJ2780:[Spoj]8093 Sevenk Love Oimaster 后缀自动机+离线+dfs序+树状数组
BZOJ3277:串 后缀自动机+离线处理+树状数组(&&BZOJ3473)

BZOJ1396:识别子串 后缀自动机+并查集(&&BZOJ2865)

shinbokuow posted @ Jan 14, 2015 03:57:31 PM in BZOJ with tags 后缀自动机 并查集 , 1736 阅读

思路:

我们建立原串的后缀树,那么发现出现次数为1的子串仅能出现在叶子节点上的父亲边上.(说起来很容易)

然后发现每一个更新可以分解为两端,每一段可以相当于一条斜率恒定的线段.

因此我们将两段分开,按照截距从小到大排序,并用并查集模拟覆盖即可.

(说起来很容易)

#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
using namespace std;
 
#define N 100010
struct Node{
    Node*tranc[26],*pa;int len,begin,siz,deg;
    Node(){}
    Node(int _len,int _begin):len(_len),begin(_begin){}
}Tnull,*null=&Tnull,mem[N<<1],*P=mem,*root,*last;
Node*Newnode(int _len,int _begin){
    P->len=_len,P->begin=_begin;for(int i=0;i<26;++i)P->tranc[i]=null;P->pa=null;return P++;
}
 
char s[N];
 
struct Interval{
    int l,r,k;
    Interval(){}
    Interval(int _l,int _r,int _k):l(_l),r(_r),k(_k){}
    bool operator<(const Interval&B)const{return k<B.k;}
}S[N],S2[N];
 
int r[N];
inline void reset(int n){
    for(register int i=1;i<=n+1;++i)r[i]=i;
}
inline int find(int x){
    int q=x,rq;for(;x!=r[x];x=r[x]);for(;q!=x;q=rq)rq=r[q],r[q]=x;return x;
}
 
int v[N],vv[N];
 
Node*q[N<<1];int fr,ta;
 
int main(){
    scanf("%s",s+1);int l=strlen(s+1);
    register int i,j;int y;Node*p,*np,*q,*nq;
    for(last=root=Newnode(0,0),i=l;i>=1;--i){
        np=Newnode(last->len+1,i);np->siz=1;
        for(p=last,y=s[i]-'a';p!=null&&p->tranc[y]==null;p=p->pa)p->tranc[y]=np;
        if(p==null)np->pa=root;
        else{
            q=p->tranc[y];
            if(q->len==p->len+1)np->pa=q;
            else{
                nq=Newnode(p->len+1,0);nq->pa=q->pa,q->pa=np->pa=nq;
                memcpy(nq->tranc,q->tranc,sizeof q->tranc);
                for(;p!=null&&p->tranc[y]==q;p=p->pa)p->tranc[y]=nq;
            }
        }last=np;
    }
     
    for(p=mem;p<P;++p)++p->pa->deg;
    for(p=mem;p<P;++p)if(p->deg==0)::q[ta++]=p;
    while(fr^ta){
        p=::q[fr++];
        if(p->pa!=null){
            p->pa->siz+=p->siz;
            if(!--p->pa->deg)
                ::q[ta++]=p->pa;
        }
    }
     
    int id=0,id2=0;
    for(p=mem;p<P;++p){
        if(p->siz==1){
            //printf("%d %d %d\n",p->begin,p->len,p->pa->len);
            S[++id]=Interval(l-(p->len-p->pa->len)+1,l,1-p->begin);
            S2[++id2]=Interval(p->begin,S[id].l-1,S[id].l-p->begin+1);
        }
    }sort(S+1,S+id+1),sort(S2+1,S2+id2+1);
     
    reset(l);
    memset(v,0x3f,sizeof v);
    for(i=1;i<=id;++i){
        for(j=find(S[i].l);j<=S[i].r;j=r[j]){
            if(v[j]==0x3f3f3f3f)v[j]=S[i].k;
            r[j]=find(j+1);
        }
    }
    reset(l);
    memset(vv,0x3f,sizeof vv);
    for(i=1;i<=id2;++i){
        for(j=find(S2[i].l);j<=S2[i].r;j=r[j]){
            if(vv[j]==0x3f3f3f3f)vv[j]=S2[i].k;
            r[j]=find(j+1);
        }
    }
     
    for(i=1;i<=l;++i)printf("%d\n",min(l,min(v[i]+i,vv[i])));
     
    return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter