ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

支持双端插入的可撤销回文自动机

2022-09-08 14:30:47  阅读:175  来源: 互联网

标签:pre nxt suf 双端 len quick nodes 自动机 回文


支持双端插入的可撤销回文自动机


打多校看到的科技,板子++
参考来源:https://ac.nowcoder.com/acm/contest/view-submission?submissionId=53195473

template <class T, int SIZE, T offset>
struct Depam
{
    struct Node
    {
        int len, pos, fail;
        int nxt[SIZE], quick[SIZE];
    };
    vector<Node> nodes;
    int          nodelen, pre, suf;  // pre和suf分别记录首尾的末端节点

    int       nL, nR;  //大小
    int       l, r;    //首尾位置
    vector<T> s;       //字符串

    int                    hislen;
    vector<pair<int, int>> his;  // history历史操作

    Depam(int nL_, int nR_) : nL(nL_), nR(nR_)
    {
        nodelen = 2;
        pre = suf = 0;
        nodes.resize(2 + nL + nR);
        nodes[0].len = 0, nodes[0].pos = 0, nodes[0].fail = 1;
        nodes[1].len = -1, nodes[1].pos = 0, nodes[1].fail = 1;
        memset(nodes[0].nxt, 0, sizeof(nodes[0].nxt));
        memset(nodes[1].nxt, 0, sizeof(nodes[1].nxt));
        for (int a = 0; a < SIZE; a++)
            nodes[0].quick[a] = 1;
        for (int a = 0; a < SIZE; a++)
            nodes[1].quick[a] = 1;
        l = r = 1 + nL;
        s.assign(1 + nL + nR + 1, offset - 1);  //初始化为空
        hislen = 0;
        his.resize(nL + nR);
    }
    void pushFront(T t)
    {
        assert(1 < l);
        const int a   = t - offset;
        his[hislen++] = make_pair(~pre, -1);
        s[--l]        = t;
        if (s[l + 1 + nodes[pre].len] != t)  //如果不匹配,则跳到最近可以匹配的位置
            pre = nodes[pre].quick[a];
        Node& f = nodes[pre];
        if (!f.nxt[a]) {
            his[hislen - 1].second = pre;
            Node& g                = nodes[nodelen];
            g.len                  = f.len + 2;
            g.pos                  = l;
            g.fail                 = nodes[f.quick[a]].nxt[a];  //参照普通pam流程,在这种写法下只用跳一次
            memset(g.nxt, 0, sizeof(g.nxt));
            memcpy(g.quick, nodes[g.fail].quick, sizeof(g.quick));
            g.quick[s[l + nodes[g.fail].len] - offset] = g.fail;  //用fail更新quick数组
            f.nxt[a]                                   = nodelen++;
            // ans += g.dep;
        }
        if (nodes[pre = f.nxt[a]].len == r - l)
            suf = pre;
    }
    void pushBack(T t)
    {  //同上,不再赘述
        assert(r < 1 + nL + nR);
        const int a   = t - offset;
        his[hislen++] = make_pair(suf, -1);
        s[r++]        = t;
        if (s[r - 2 - nodes[suf].len] != t)
            suf = nodes[suf].quick[a];
        Node& f = nodes[suf];
        if (!f.nxt[a]) {
            his[hislen - 1].second = suf;
            Node& g                = nodes[nodelen];
            g.len                  = f.len + 2;
            g.pos                  = r - g.len;
            g.fail                 = nodes[f.quick[a]].nxt[a];
            memset(g.nxt, 0, sizeof(g.nxt));
            memcpy(g.quick, nodes[g.fail].quick, sizeof(g.quick));
            g.quick[s[r - 1 - nodes[g.fail].len] - offset] = g.fail;
            f.nxt[a]                                       = nodelen++;
            // ans += g.dep;
        }
        if (nodes[suf = f.nxt[a]].len == r - l)
            pre = suf;
    }
    void undo()
    {
        const pair<int, int> h = his[--hislen];  //找到上一次操作的内容 first是树上的标号,second是字符串中的位置
        if (h.first < 0) {
            // pushFront
            if (nodes[pre].len == r - l)
                suf = nodes[suf].fail;
            pre = ~h.first;
            if (~h.second) {
                --nodelen;
                nodes[h.second].nxt[s[l] - offset] = 0;
            }
            s[l++] = offset - 1;
        }
        else {
            // pushBack
            if (nodes[suf].len == r - l)
                pre = nodes[pre].fail;
            suf = h.first;
            if (~h.second) {
                --nodelen;
                nodes[h.second].nxt[s[r - 1] - offset] = 0;
            }
            s[--r] = offset - 1;
        }
    }
    /////模板自带的debug工具,看不懂,有机会用用看
    void dfsPrint(ostream& os, int u, const string& branch, int type) const
    {
        const Node& f = nodes[u];
        os << branch << ((type == 0) ? "" : (type == 1) ? "|-- " :
                                                          "`-- ");
        if (f.len <= 0) {
            os << "(" << f.len << ")";
        }
        else {
            for (int i = f.pos; i < f.pos + f.len; ++i)
                os << s[i];
        }
        os << " " << u << " " << f.fail;
        // debug here
        os << "\n";
        int a0 = -1;
        for (int a = 0; a < SIZE; ++a)
            if (f.nxt[a])
                a0 = a;
        for (int a = 0; a < SIZE; ++a)
            if (f.nxt[a]) {
                dfsPrint(os, f.nxt[a], branch + ((type == 0) ? "" : (type == 1) ? "|   " :
                                                                                  "    "),
                         (a == a0) ? 2 : 1);
            }
    }
    friend ostream& operator<<(ostream& os, const Depam& depam)
    {
        depam.dfsPrint(os, 0, "  ", 0);
        depam.dfsPrint(os, 1, "", 0);
        return os;
    }
};

Depam<char, 26, 'a'> t(0, 0);
// t = decltype(t)(n, n);

标签:pre,nxt,suf,双端,len,quick,nodes,自动机,回文
来源: https://www.cnblogs.com/iceyz/p/16669311.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有