zoukankan      html  css  js  c++  java
  • Wannafly Camp 2020 Day 2D 卡拉巴什的字符串

    动态维护任意两个后缀的lcp集合的mex,支持在串末尾追加字符。

    Solution

    考虑在 SAM 上求两个后缀的 LCP 的过程,无非就是找它们在 fail 树上的 LCA,那么 LCP 长度就是这个点的 maxlen

    那么在这里,当增量添加的时候,如果一个节点有了儿子,那么它就可能成为一个新的 LCP

    于是我们在操作父子关系的时候暴力修改一个 bool 数组即可,答案的维护是均摊 (O(n))

    注意需要对输出 (0) 的情况做特判,比如这个例子

    aaaabbbbab

    输出的结果应该是

    0 0 0 0 4 4 4 4 4 4

    居然又卡空格

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 2000005;
    
    int pin=0;
    bool b[N];
    vector <int> mem;
    
    void push(int x) {
        b[x]=1;
        while(b[pin]) ++pin;
        mem.push_back(x);
    }
    
    void clear() {
        for(int x:mem) b[x]=0;
        mem.clear();
        pin=0;
    }
    
    struct Suffix_Automata {
        int maxlen[N], trans[N][26], link[N], Size, Last;
        int t[N], a[N], cnt[N];
        Suffix_Automata() { Size = Last = 1; }
        void clear() {
            for(int i=1;i<=Size;i++) {
                maxlen[i]=link[i]=t[i]=a[i]=cnt[i]=0;
                memset(trans[i],0,sizeof trans[i]);
            }
            Size = Last = 1;
        }
        inline void Extend(int id) {
            int cur = (++ Size), p;
            maxlen[cur] = maxlen[Last] + 1;
            cnt[cur] = 1;
            for (p = Last; p && !trans[p][id]; p = link[p]) trans[p][id] = cur;
            if (!p) link[cur] = 1, push(maxlen[1]);
            else {
                int q = trans[p][id];
                if (maxlen[q] == maxlen[p] + 1) link[cur] = q, push(maxlen[q]);
                else {
                    int clone = (++ Size);
                    maxlen[clone] = maxlen[p] + 1;
                    for(int i=0;i<26;i++) trans[clone][i] = trans[q][i];
                    link[clone] = link[q]; push(maxlen[link[q]]);
                    for (; p && trans[p][id] == q; p = link[p]) trans[p][id] = clone;
                    link[cur] = link[q] = clone; push(maxlen[clone]); push(maxlen[clone]);
                }
            }
            Last = cur;
        }
    } sam;
    char str[N];
    int buc[26],tot;
    signed main() {
        int T;
        scanf("%d",&T);
        while(T--) {
            tot=0;memset(buc,0,sizeof buc);
            scanf("%s",str+1);
            sam.clear();
            int len=strlen(str+1);
            for(int i=1;i<=len;i++) {
                if(buc[str[i]-'a']==0) ++tot;
                buc[str[i]-'a']++;
                sam.Extend(str[i]-'a');
                printf("%d%s",(tot>1)*pin,i==len?"":" ");
            }
            puts("");
            clear();
        }
    }
    
    
  • 相关阅读:
    我的2015羊年总结
    谈对象 MVC 和 多端
    自建博客随想录
    梦说1+1等于多少
    多媒体文件格式全解说(下)--图片
    多媒体文件格式全解说(上)--音视频
    做一个“代码模块”交易的网站
    写个屏蔽百度搜索广告的Chrome插件
    Go 系列教程 —— 5. 常量
    Go 系列教程 —— 4. 类型
  • 原文地址:https://www.cnblogs.com/mollnn/p/12335662.html
Copyright © 2011-2022 走看看