Description
UPD:本題字符集爲全體小寫字母
Input
Output
Solution
這題我寫了一個查詢前暴力get_fail的,複雜度爆炸,但數據水,過了
時間複雜度:O(mlogm)
正解是用所有的s建AC自動機,再建fail樹,最後用樹狀數組維護各種字符串的個數(假的強制在線)。
前序遍歷fail樹,得到dfn,就可以愉快地維護樹狀數組查詢答案了~
關於fail樹可以看看這裏:https://blog.csdn.net/niiick/article/details/87947160
tips:把查詢的s也插入AC自動機其實對解題沒有影響,因爲最後統計的實際是每個操作1和操作2對某段區間的貢獻,即某段區間的點代表的字符串都包含該串。
但是實際上出題人的意思是通過二進制分組,建立個AC自動機,使用類似啓發式合併的方法將size相同的AC自動機合併,這樣每個字符串最多被插入次,時間複雜度O(mlogm)。(想想就覺得不會打麻煩)
Code
給的是某位AK比賽的學長的代碼,rp++
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const int N=2000005;
int m,l,tot=1,len[N],bg[N],fail[N],num[N],ch[N][26];
int cnt,idx,nt,head[N],to[N],nxt[N],dfn[N],siz[N],ck[N];
ll c[N],mask,ans,val[N],op[N];
char s[N],str[N];
void adde(int u,int v){
to[++cnt]=v;
nxt[cnt]=head[u];
head[u]=cnt;
}
void insert(char s[],int id){
int k=1;
for(int i=0;i<len[id];i++){
int x=s[i]-'a';
if(!ch[k][x]){
ch[k][x]=++tot;
}
k=ch[k][x];
}
num[id]=k;
}
void build(){
queue<int> q;
q.push(1);
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=0;i<26;i++){
int p=u==1?1:ch[fail[u]][i];
if(ch[u][i]){
fail[ch[u][i]]=p;
q.push(ch[u][i]);
}else{
ch[u][i]=p;
}
}
}
for(int i=2;i<=tot;i++){
adde(fail[i],i);
}
}
void dfs(int u){
dfn[u]=++idx;
siz[u]=1;
int v;
for(int i=head[u];i;i=nxt[i]){
v=to[i];
dfs(v);
siz[u]+=siz[v];
}
}
void add(int i,int v){
for(;i<=idx;i+=i&(-i)){
c[i]+=v;
}
}
ll query(int i){
ll res=0;
for(;i;i-=i&(-i)){
res+=c[i];
}
return res;
}
void go(int l,int r){
nt++;
int k=1;
for(int i=l;i<=r;i++){
int x=s[i]-'a';
k=ch[k][x];
if(cxk[k]==nt){//cxk僅僅用於卡常 CXKNMSL(霧
ans+=val[k];
}else{
cxk[k]=nt;
val[k]=query(dfn[k]);
ans+=val[k];
}
}
}
int main(){
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%lld%s",&op[i],str);
len[i]=strlen(str);
bg[i]=l+1;
insert(str,i);
for(int j=0;j<len[i];j++){
s[++l]=str[j];
}
}
build();
dfs(1);
for(int i=1;i<=m;i++){
op[i]^=mask;
if(op[i]==1){
add(dfn[num[i]],1);
add(dfn[num[i]]+siz[num[i]],-1);
}else if(op[i]==2){
add(dfn[num[i]],-1);
add(dfn[num[i]]+siz[num[i]],1);
}else{
ans=0;
go(bg[i],bg[i]+len[i]-1);
printf("%lld\n",ans);
mask^=labs(ans);
}
}
return 0;
}