支持双端插入的可撤销回文自动机
作者:互联网
支持双端插入的可撤销回文自动机
打多校看到的科技,板子++
参考来源: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