BZOJ2555 Substring
朴素的想法是直接用SAM模拟,但是这样的话每次归并排序会T掉……
考虑到每次的影响,对于初始的SAM来说,我们每次新加入一个点,那么就会使这个点到\(t_0\)状态的路径上所有的点全部权值+1,于是我们需要维护路径,同时还需要支持动态插入,那就是LCT了。
于是乎我们需要用LCT来维护SAM的parent树,其实也不是很难……就是每次在SAM更改parent树的时候LCT照着做就行了。因为这题树不会有什么换根之类的乱七八糟的东西,所以不需要\(reverse\),不需要\(makeroot\)……(orz LCT都快忘光了)
然后也不需要pushup(你也不用维护子树信息啊_) 直接每次在修改的时候打个标记pushdown就好了。
最后要注意的一点是,在query的时候如果没有匹配要直接退出。然后如果匹配到的话需要先把这个节点splay到根再计算。
#include<bits/stdc++.h>
#define rep(i,a,n) for(register int i = a;i <= n;i++)
#define per(i,n,a) for(register int i = n;i >= a;i--)
#define enter putchar('\n')
#define pr pair<int,int>
#define mp make_pair
#define fi first
#define sc second
using namespace std;
typedef long long ll;
const int M = 600005;
const int N = 3000005;
const int INF = 2147483647;
int read()
{
int ans = 0,op = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
while(ch >='0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
return ans * op;
}
int Q,n,mask;
char s[N];
string chars;
void gets(int mask)
{
scanf("%s",s),chars = s;
int k = chars.length()-1;
rep(j,0,k)
{
mask = (mask * 131 + j) % chars.length();
char t = chars[j];
chars[j] = chars[mask],chars[mask] = t;
}
}
struct LCT
{
int ch[M<<1][2],tag[M<<1],val[M<<1],fa[M<<1],top,sta[M<<1];
bool get(int x) {return ch[fa[x]][1] == x;}
bool nroot(int x) {return (ch[fa[x]][1] == x) || (ch[fa[x]][0] == x);}
void add(int x,int y) {if(x) val[x] += y,tag[x] += y;}
void pushdown(int x)
{
if(tag[x] != 0)
{
int l = ch[x][0],r = ch[x][1];
add(l,tag[x]),add(r,tag[x]),tag[x] = 0;
}
}
void rotate(int x)
{
int y = fa[x],z = fa[y],k = get(x);
if(nroot(y)) ch[z][get(y)] = x;
fa[x] = z,ch[y][k] = ch[x][k^1],fa[ch[x][k^1]] = y;
ch[x][k^1] = y,fa[y] = x;
}
void splay(int x)
{
top = 0;
int p = x;
sta[++top] = p;
while(nroot(p)) p = fa[p],sta[++top] = p;
while(top) pushdown(sta[top--]);
while(nroot(x))
{
int y = fa[x],z = fa[y];
if(nroot(y)) ((ch[z][0] == y) ^ (ch[y][0] == x)) ? rotate(x) : rotate(y);
rotate(x);
}
}
void access(int x) {for(int t = 0;x;t = x,x = fa[x]) splay(x),ch[x][1] = t;}
void link(int x,int y)
{
fa[x] = y;
access(y),splay(y),add(y,val[x]);
}
void cut(int x)
{
access(x),splay(x);
add(ch[x][0],-val[x]);
fa[ch[x][0]] = 0,ch[x][0] = 0;
}
}T;
struct Suffix
{
int last,cnt,ch[M<<1][26],fa[M<<1],l[M<<1];
void extend(int c)
{
int p = last,np = ++cnt;
l[np] = l[p] + 1,last = cnt,T.val[np] = 1;
while(p && !ch[p][c]) ch[p][c] = np,p = fa[p];
if(!p) {fa[np] = 1,T.link(np,1);return;}
int q = ch[p][c];
if(l[q] == l[p] + 1) fa[np] = q,T.link(np,q);
else
{
int nq = ++cnt;
l[nq] = l[p] + 1,memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq] = fa[q],T.link(nq,fa[q]);
fa[np] = fa[q] = nq,T.cut(q),T.link(np,nq),T.link(q,nq);
while(ch[p][c] == q) ch[p][c] = nq,p = fa[p];
}
}
void add()
{
gets(mask);
int d = chars.length()-1;
rep(i,0,d) extend(chars[i] - 'A');
}
int query()
{
gets(mask);
int d = chars.length()-1,u = 1;
rep(i,0,d)
{
int c = chars[i] - 'A';
if(!ch[u][c]) return 0;
u = ch[u][c];
}
T.splay(u);
return T.val[u];
}
}SAM;
int main()
{
Q = read(),SAM.last = SAM.cnt = 1;
scanf("%s",s+1),n = strlen(s+1);
rep(i,1,n) SAM.extend(s[i] - 'A');
while(Q--)
{
scanf("%s",s);
if(s[0] == 'A') SAM.add();
else
{
int ans = SAM.query();
printf("%d\n",ans),mask ^= ans;
}
}
return 0;
}
当你意识到,每个上一秒都成为永恒。