• 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
    ",ans-sa.calc_());
        }
    }
    View Code
  • 相关阅读:
    【原创游戏】合金弹头S——Unity制作的同人游戏
    【原创游戏】Extreme Ball——虐心小游戏
    【原创游戏】迷踪失路——恐怖风格的第一人称迷宫游戏
    生成二维码工具类及使用
    使用base64对图片的加密解密
    将图片转换成二进制, (用到 输入流,输出流)
    图片的缩放(放大缩小)
    逻辑推理
    应该在别人恐惧时贪婪吗?
    SQL 2005数据类型说明
  • 原文地址:https://www.cnblogs.com/asd123www/p/9778163.html
Copyright © 2020-2023  润新知