题面
题意
有2种操作:
1.学习一个字符串(已学过则不算)
2.查询某个字符串中有几个学过了。
强制在线
做法
如果不用在线,则离线建AC自动机,轻松解决。
但是,题目要求强制在线,可以发现,随着新串的加入,AC自动机上节点的fail指针也会随之改变,因此AC自动机必须重构,但若直接重构必然会T。
因此,可以考虑分块的思想,建两个AC自动机a,b,每次将字符串加入到b中,加入后在下一次询问前暴力重构,若加入后,其节点数大于阈值(sqrt(节点总数)),则将这些字符串加入a中并重构,再将b清零即可。
查询时,在a,b中分别查询,两个自动机的答案之和即为最终答案。
去重只要哈希+map即可。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<map>
#define ll long long
#define base 127
#define S 500
#define N 100100
#define M 484701863
using namespace std;
ll T,TT,n,m,ans,last;
bool more,cz[N];
string str[N],tmp;
queue<ll>que;
struct AC
{
int tt;
struct Node
{
ll son[2],fail,cs,yl;
void init()
{
yl=cs=fail=son[0]=son[1]=0;
}
} node[N];
void init()
{
int i;
for(i=0; i<=tt; i++) node[i].init();
tt=0;
}
void build()
{
ll i,j,k,p,q;
for(i=0; i<2; i++)
{
if(node[0].son[i])
{
node[node[0].son[i]].fail=0;
node[node[0].son[i]].cs=node[node[0].son[i]].yl;
que.push(node[0].son[i]);
}
}
for(; !que.empty();)
{
p=que.front();
que.pop();
for(i=0; i<2; i++)
{
if(!node[p].son[i]) continue;
for(k=node[p].fail; k&&!node[k].son[i]; k=node[k].fail);
node[node[p].son[i]].fail=node[k].son[i];
node[node[p].son[i]].cs=node[node[k].son[i]].cs+node[node[p].son[i]].yl;
que.push(node[p].son[i]);
}
}
}
inline void add(ll v)
{
ll i,j,u,now=0;
for(i=1; i<str[v].size(); i++)
{
u=str[v][i]-'0';
if(!node[now].son[u])
{
node[now].son[u]=++tt;
}
now=node[now].son[u];
}
// puts(" 666");
// cout<<" "<<now<<" "<<endl;
node[now].yl=1;
}
inline ll find(ll v)
{
ll i,u,now=0,res=0;
// out();
for(i=1; i<str[v].size(); i++)
{
u=str[v][i]-'0';
for(; now&&!node[now].son[u]; now=node[now].fail);
now=node[now].son[u];
res+=node[now].cs;
}
return res;
}
inline void out()
{
int i,j;
puts("");
for(j=0; j<=tt; j++) cout<<node[j].son[0]<<" "<<node[j].son[1]<<" "<<node[j].yl<<" "<<node[j].cs<<endl;
puts("");
puts("");
}
};
AC a,b;
map<ll,bool>mm;
inline ll po(ll u,ll v)
{
ll res=1;
for(; v;)
{
if(v&1) res=res*u%M;
u=u*u%M;
v>>=1;
}
return res;
}
inline void hb(ll u)
{
ll i;
b.init();
for(i=last; i<=u; i++)
{
if(cz[i])
a.add(i);
}
a.build();
last=u+1;
}
ll hsh(string u)
{
ll i,res=base;
for(i=0; i<u.size(); i++)
{
res=po(res+u[i],u[i]);
}
return res;
}
int main()
{
ios::sync_with_stdio(0);
ll i,j,p,q,o,t;
cin>>T;
while(T--)
{
++TT;
cout<<"Case #"<<TT<<":"<<endl;
mm.clear();
a.init(),b.init();
last=1;
more=ans=0;
cin>>n;
for(i=1; i<=n; i++)
{
cin>>tmp;
str[i]=tmp;
for(j=1; j<tmp.size(); j++)
{
str[i][j]=tmp[(ans+j-1)%(tmp.size()-1)+1];
}
// cout<<" "<<str[i]<<endl;
if(str[i][0]=='+')
{
cz[i]=1;
t=hsh(str[i]);
if(mm.count(t)) continue;
more=1;
mm[t]=1;
b.add(i);
if(b.tt>S) hb(i);
}
else
{
cz[i]=0;
if(more) b.build(),more=0;
ans=a.find(i)+b.find(i);
cout<<ans<<endl;
}
}
}
}