NOI2018 你的名字

终于将后缀自动机,后缀树理解了。

学习了后缀自动机转后缀树,真的不用后缀数组了。

68分就是广义后缀自动机的思路。

我直接在原串的自动机上插一边询问串,再逐个恢复即可。这样是线性的。

剩下的就是区间询问了。

对于询问串的每个$l$,满足右端点在$[pos+1,n]$的串不在$S$中出现的是一个区间。

并且随着$l$的增加$pos$单调移动。

这样我们就可以求出可重的在$S$中未出现的串。

然后用后缀数组的$height$去掉重复统计的就行了。

 

反串的后缀自动机的$fail$树是正串的后缀树。

挺好理解的,但是注意后缀树中每个后缀都变成了$S[i+1,n]*$。

即保证了每个后缀都有一个不同的节点。

建出后缀树之后就可以按照边的大小顺序$dfs$得到所有后缀的排名了。

我一开始在疑惑怎么比较后缀树节点每个出边代表字符串的大小。

出边都不同了第一个字符肯定不同啊。。。

#include <bits/stdc++.h>
#define for1(a,b,i) for(int i=a;i<=b;++i)
#define FOR2(a,b,i) for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
inline int read() {
    int f=1,sum=0;
    char x=getchar();
    for(;(x<'0'||x>'9');x=getchar()) if(x=='-') f=-1;
    for(;x>='0'&&x<='9';x=getchar()) sum=sum*10+x-'0';
    return f*sum;
}

#define M 1000005
#define N 20000005
int n,m;
char s[M];
vector <int> to[M];
int sz,L[M],R[M],a[M];
int h[M],num,root[M],ch[N][2];

struct Suffix_Automaton {
    int las,node_num;
    int mx[M],fa[M],pos[M],nxt[M][26];
    
    inline void init() {
        las=node_num=1;
    }
    
    inline void clear() {
        las=0;
        for1(1,node_num,i) {
            mx[i]=fa[i]=pos[i]=0;
            memset(nxt[i],0,sizeof(nxt[i]));
        }
        node_num=0;
    }
    
    inline void extend_(int c) {
        int p=las,np=las=++node_num;
        mx[np]=mx[p]+1;
        while (p&&!nxt[p][c]) nxt[p][c]=np,p=fa[p];
        if(!p) fa[np]=1;
        else {
            int q=nxt[p][c];
            if(mx[q]==mx[p]+1) fa[np]=q;
            else {
                int nq=++node_num;
                mx[nq]=mx[p]+1;
                memcpy(nxt[nq],nxt[q],sizeof(nxt[q]));
                fa[nq]=fa[q],fa[q]=fa[np]=nq;
                while (nxt[p][c]==q) nxt[p][c]=nq,p=fa[p];
            }
        }
    }
}sam,Y;

struct Suffix_Array {
    int f[M],g[M],cnt;
    int sa_[M],rank_[M];
    int pos[M],buc[M],sta[M];
    vector <pair<int,int> >vis[M];
    
    inline void dfs(int x) {
        int size=vis[x].size();
        if(pos[x]) {
            ++cnt;
            sa_[cnt]=m-Y.mx[x]+1;
            rank_[m-Y.mx[x]+1]=cnt;
        }
        for1(1,size,i) dfs(vis[x][i-1].second);
    }
    
    inline void build() {
        Y.clear(),Y.init();
        FOR2(m,1,i) Y.extend_(s[i]-'a'),f[Y.las]=m-i+1,pos[Y.las]=1;
        for1(1,Y.node_num,i) ++buc[Y.mx[i]];
        for1(1,m,i) buc[i]+=buc[i-1];
        for1(1,Y.node_num,i) sta[buc[Y.mx[i]]--]=i;
        FOR2(Y.node_num,1,i) f[Y.fa[sta[i]]]=f[sta[i]];
        for1(2,Y.node_num,i) vis[Y.fa[i]].push_back(make_pair(s[m-f[i]+Y.mx[Y.fa[i]]+1],i));
        for1(1,Y.node_num,i) sort(vis[i].begin(),vis[i].end());
        dfs(1);
        cnt=0;
        for1(1,Y.node_num,i) buc[i]=pos[i]=0,vis[i].clear();
    }
    
    inline ll calc_() {
        int x=0;
        ll ans=0;
        for1(1,m,i) {
            while (s[i+x]==s[sa_[rank_[i]-1]+x]) ++x;
            g[rank_[i]]=x,x-=x!=0;
        }
        for1(1,m,i) {
            x=sa_[i];
            if(x+g[i]-1>h[x]) ans+=x+g[i]-1-h[x];
        }
        return ans;
    }
}sa;

inline void T_add(int &g,int l,int r,int x) {
    if(!g) g=++num;
    if(l==r) return;
    int mid=l+r>>1;
    if(x<=mid) T_add(ch[g][0],l,mid,x);
    else       T_add(ch[g][1],mid+1,r,x);
}

inline void Merge(int u,int &v,int l,int r) {
    if(!u) return;
    if(!v) return v=u,void();
    int mid=l+r>>1;
    Merge(ch[u][0],ch[v][0],l,mid);
    Merge(ch[u][1],ch[v][1],mid+1,r);
}

inline void dfs(int x) {
    L[x]=sz+1;
    if(sam.pos[x]) {
        ++sz;
        T_add(root[sz],1,n,sam.pos[x]);
        Merge(root[sz-1],root[sz],1,n);
    }
    int tot=to[x].size();
    for1(1,tot,i) dfs(to[x][i-1]);
    R[x]=sz;
}

inline int query(int u,int v,int l,int r,int x) {
    if(v==u||l>x) return 0;
    if(l==r) return l;
    int ans=0;
    int mid=l+r>>1;
    ans=query(ch[u][1],ch[v][1],mid+1,r,x);
    if(ans) return ans;
    return query(ch[u][0],ch[v][0],l,mid,x);
}

int main () {
    //freopen("a.in","r",stdin);
    scanf("%s",s+1);
    n=strlen(s+1);
    
    sam.init();
    for1(1,n,i) sam.extend_(s[i]-'a'),sam.pos[sam.las]=i;
    for1(2,sam.node_num,i) to[sam.fa[i]].push_back(i);
    
    bool vis=0;
    
    int q_size=read();
    while (q_size--) {
        int l,r;
        scanf("%s%d%d",s+1,&l,&r);
        if(!(l==1&&r==n)&&!vis) vis=1,dfs(1);
        m=strlen(s+1);
        sa.build();
        
        ll ans=0;
        int now=1;
        for1(1,m,i) {
            h[i]=max(h[i-1],i-1);
            while (sam.nxt[now][s[h[i]+1]-'a']) {
                int ha=sam.nxt[now][s[h[i]+1]-'a'];
                if(!(l==1&&r==n)&&query(root[L[ha]-1],root[R[ha]],1,n,r)-h[i]+i-1<l) break;
                ++h[i],now=ha;
                if(h[i]==m) break;
            }
            if(h[i]==m) {
                for1(i+1,m,j) h[j]=m;
                break;
            }
            ans+=m-h[i];
            if(sam.mx[sam.fa[now]]==h[i]-i) now=sam.fa[now];
        }
        printf("%lld\n",ans-sa.calc_());
    }
}
View Code

 

posted @ 2018-10-12 14:57  asd123www  阅读(684)  评论(0编辑  收藏  举报