其他分享
首页 > 其他分享> > 支持双端插入的可撤销回文自动机

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

作者:互联网

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


打多校看到的科技,板子++
参考来源: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