Luogu P5212 【SubString】
Description
Solution
动态加入字符就用\(SAM\),发现答案就是一个点的子树的\(siz\)之和,所以需要动态维护子树和,上\(LCT\)。
\(lCT\)上每个节点,\(siz\)表示\(Splay\)上大小,\(lsiz\)表示虚子树大小,修改\(Update\)、\(Access\)、\(Link\)函数进行修改即可。
最后答案就是\(Splay\)上深度比它大的节点的\(siz\)之和加上它的虚子树大小,如果它是字符串的前缀,再加一。
Code
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 1200050;
const int INF = 999999999;
int fa[N], son[N][26], last = 1, cnt = 1, len[N], rev[N], n, mask, ans;
char s[3000050];
struct LCT
{
int son[2], siz, lsiz, fa, v;
} tr[N + 50];
bool Is(int x)
{
return tr[tr[x].fa].son[1] != x && tr[tr[x].fa].son[0] != x;
}
int Get(int x)
{
return tr[tr[x].fa].son[1] == x;
}
void Rv(int x)
{
rev[x] ^= 1;
swap(tr[x].son[0], tr[x].son[1]);
return;
}
void Pushdown(int x)
{
if (rev[x])
{
if (tr[x].son[0]) Rv(tr[x].son[0]);
if (tr[x].son[1]) Rv(tr[x].son[1]);
rev[x] = 0;
return;
}
}
void Update(int x)
{
tr[x].siz = tr[tr[x].son[0]].siz + tr[tr[x].son[1]].siz + tr[x].lsiz + tr[x].v;
return;
}
void Rotate(int x)
{
int f = tr[x].fa, p = tr[f].fa, d = Get(x);
if (!Is(f)) tr[p].son[Get(f)] = x;
tr[x].fa = p;
tr[f].son[d] = tr[x].son[d ^ 1];
if (tr[f].son[d]) tr[tr[f].son[d]].fa = f;
tr[x].son[d ^ 1] = f;
tr[f].fa = x;
Update(f);
Update(x);
return;
}//旋转,记得判断父亲是不是splay的根
void Calc(int x)
{
if (!Is(x)) Calc(tr[x].fa);
Pushdown(x);
return;
}//递归处理标记
void Splay(int x)
{
Calc(x);
while (!Is(x))
{
int f = tr[x].fa;
if (!Is(f))
Get(f) ^ Get(x) ? Rotate(x) : Rotate(f);
Rotate(x);
}
return;
}
void Access(int x)
{
int p = 0;
while (x)
{
Splay(x);
tr[x].lsiz += tr[tr[x].son[1]].siz - tr[p].siz;
tr[x].son[1] = p;
Update(x);
p = x;
x = tr[x].fa;
}
return;
}
void Makeroot(int x)
{
Access(x);
Splay(x);
Rv(x);
return;
}
int Findroot(int x)
{
Access(x);
Splay(x);
while (tr[x].son[0]) Pushdown(x), x = tr[x].son[0];
Splay(x);
return x;
}
void Link(int u, int v)
{
Makeroot(u);
if (Findroot(v) == u) return;
tr[u].fa = v; tr[v].lsiz += tr[u].siz;
Update(v);
return;
}
void Cut(int u, int v)
{
Makeroot(u);
if (Findroot(v) != u || tr[v].fa != u || tr[v].son[0]) return;
tr[u].son[1] = tr[v].fa = 0;
Update(u);
return;
}
int Askk(int x)
{
Makeroot(1); Access(x); Splay(x);
return tr[x].lsiz + tr[x].v + tr[tr[x].son[1]].siz;
}
void Init(int x)
{
tr[x].siz = tr[x].v = 1;
return;
}
void Change(int x, int y)
{
if (fa[x]) Cut(x, fa[x]);
Link(x, fa[x] = y);
return;
}
void Insert(int c)
{
int p = last, ne = last = ++cnt;
len[ne] = len[p] + 1; Init(ne);
while (p && !son[p][c]) son[p][c] = ne, p = fa[p];
if (!p) { Change(ne, 1); return; }
int q = son[p][c];
if (len[q] == len[p] + 1) { Change(ne, q); return; }
int sp = ++cnt;
for (int i = 0; i < 26; i++) son[sp][i] = son[q][i];
len[sp] = len[p] + 1;
Change(sp, fa[q]);
Change(q, sp); Change(ne, sp);
while (p && son[p][c] == q) son[p][c] = sp, p = fa[p];
return;
}
void Work()
{
scanf("%s", s); n = strlen(s);
// return;
int rec = mask;
for (int i = 0; i < n; i++)
{
rec = (rec * 131 + i) % n;
swap(s[rec], s[i]);
}
return;
}
void Ask()
{
int now = 1, ans = 0;
Work();
for (int i = 0; i < n && now; i++) now = son[now][s[i] - 'A'];
if (!now) puts("0");
else printf("%d\n", ans = Askk(now));
mask ^= ans;
return;
}
void Add()
{
Work();
for (int i = 0; i < n; i++) Insert(s[i] - 'A');
return;
}
int main()
{
int t;
char st[10];
scanf("%d", &t);
scanf("%s", s + 1);
n = strlen(s + 1);
for (int i = 1; i <= n; i++) Insert(s[i] - 'A');
while (t--)
{
scanf("%s", st + 1);
if (st[1] == 'Q') Ask();
else Add();
}
return 0;
}