https://acm.hdu.edu.cn/showproblem.php?pid=4787
每次重构AC自动机复杂度非常大,但其实可以根号重构
维护两个AC自动机,一个大,一个小,然后对操作序列分块
小分块维护当前块的AC自动机,每次操作都重构
大分块维护之前的AC自动机,每 q \sqrt q q 次操作重构
对于任意不支持修改数据结构,都可以根号重构
cpp
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar(); while(ch<'0'||
ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
#define pb push_back
//mt19937 rand(time(0));
//mt19937_64 rand(time(0));
//srand(time(0));
#define N 5000010
#define M 200010
//#define mo
int n, m, i, j, k, T, To;
int lstans;
char str[N], st[N];
vector<char>s[M];
queue<int>q;
map<int, int>mp;
void slip() {
int i, k, len;
len=strlen(str+1); k=lstans%len; ++k;
st[len+1]=0;
for(i=1; i<=len; ++i, k=(k+1)%len) {
if(!k) k=len; st[i]=str[k];
}
for(i=1; i<=len; ++i) str[i]=st[i];
}
struct AC_auto_machine {
int nxt[M][2], fail[M], p[M], tot;
vector<int>G[N];
void clear() {
for(int i=0; i<=tot; ++i) {
fail[i]=nxt[i][0]=nxt[i][1]=p[i]=0; G[i].clear();
}
tot=0;
}
void Trie(int u, int i, int id) {
if(!s[id][i]) return p[u]=1, void();
int c=s[id][i]-'0';
if(!nxt[u][c]) nxt[u][c]=++tot;
Trie(nxt[u][c], i+1, id);
}
void bfs() {
int u, v, i;
q.push(1);
while(!q.empty()) {
u=q.front(); q.pop();
for(i=0; i<=1; ++i) {
if(!nxt[u][i]) continue;
v=nxt[u][i]; k=fail[u];
while(k && !nxt[k][i]) k=fail[k];
if(nxt[k][i]) fail[v]=nxt[k][i];
else fail[v]=1;
q.push(v);
}
}
}
void dfs(int x) {
for(int y : G[x]) p[y]+=p[x], dfs(y);
}
void build(int l, int r) { //[l, r]建AC在a里面
int i, j, k;
clear();
tot=1;
for(i=l; i<=r; ++i) if(s[i][0]!=-1) Trie(1, 0, i);
bfs();
for(i=2; i<=tot; ++i) G[fail[i]].pb(i);
dfs(1);
}
int que() {
int i, j=1, ans=0;
for(i=1; str[i]; ++i) {
while(j && !nxt[j][str[i]-'0']) j=fail[j];
if(nxt[j][str[i]-'0']) j=nxt[j][str[i]-'0'];
else j=1;
ans+=p[j];
}
return ans;
}
}AC1, AC2;
signed main()
{
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
T=read();
for(To=1; To<=T; ++To) {
printf("Case #%lld:\n", To);
n=read(); m=sqrt(n); lstans=0;
AC1.clear(); AC2.clear(); mp.clear();
for(i=1; i<=n; ++i) {
scanf("%s", str); slip();
if(str[0]=='+') {
for(j=1, k=0; str[j]; ++j) k=(k*31+str[j])%998244353535353;
if(mp[k]) { s[i].pb(-1); continue;
} mp[k]=1;
for(j=1; str[j]; ++j) s[i].pb(str[j]);
s[i].pb(0);
}
else {
lstans=AC1.que()+AC2.que(); s[i].pb(-1);
printf("%lld\n", lstans);
}
if(i%m==0) AC1.build(1, i), AC2.clear();
else AC2.build(i/m*m+1, i);
}
for(i=1; i<=n; ++i) s[i].clear();
}
return 0;
}