CF710F String Set Queries
支持字符串的插入和删除。。。SAM也干不了这个事
所以可以用cdq分治+AC自动机O(nlogn)解决
但是本题强制在线~~~
我们还有一个工具,叫做二进制分组!
所以,每组建立一个AC自动机,合并的时候,AC自动机合并。最后再build失配指针
随机删除?虽然不是栈序删除了,但是,统计数量具有贡献独立性,再对删除串建立一个AC自动机集群即可!
#include<bits/stdc++.h> #define reg register int #define il inline #define numb (ch^'0') using namespace std; typedef long long ll; il void rd(int &x){ char ch;x=0;bool fl=false; while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } namespace Miracle{ const int N=3e5+5; int m; int ch[N][26]; int vis[N][26]; int fail[N],num[N],tot[N]; int rt[N],sz[N]; int cnt,totid; struct AC{ int sta[N],top; int merge(int x,int y){ // cout<<"merge "<<x<<" "<<y<<endl; if(!x||!y) return x+y; for(reg i=0;i<26;++i) ch[x][i]=merge(ch[x][i],ch[y][i]); num[x]+=num[y]; return x; } void build(int id){ queue<int>q; for(reg i=0;i<26;++i){ if(ch[rt[id]][i]) fail[vis[rt[id]][i]=ch[rt[id]][i]]=rt[id],q.push(vis[rt[id]][i]); else vis[rt[id]][i]=rt[id]; } while(!q.empty()){ int x=q.front();q.pop(); tot[x]=num[x]+tot[fail[x]]; for(reg i=0;i<26;++i){ if(ch[x][i]){ fail[vis[x][i]=ch[x][i]]=vis[fail[x]][i]; q.push(vis[x][i]); }else{ vis[x][i]=vis[fail[x]][i]; } } } } int query(char *s){ int len=strlen(s+1); int ret=0; for(reg i=1;i<=top;++i){ int id=sta[i]; int now=rt[id]; for(reg i=1;i<=len;++i){ now=vis[now][s[i]-'a']; ret+=tot[now]; } } return ret; } void ins(char *s){ int id=++totid; int len=strlen(s+1); if(!rt[id]) rt[id]=++cnt; int now=rt[id]; for(reg i=1;i<=len;++i){ int x=s[i]-'a'; ch[now][x]=++cnt; now=ch[now][x]; } ++num[now]; //dfs(rt[id]); // cout<<rt[id]<<" "<<cnt<<endl; sz[id]=1; // cout<<" after ins "<<id<<endl; while(top&&sz[sta[top]]==sz[id]) rt[id]=merge(rt[id],rt[sta[top]]),sz[id]+=sz[sta[top]],--top; // cout<<" after merge "<<endl; build(id); sta[++top]=id; } }f,d; char s[N]; int main(){ rd(m); int op; for(reg i=1;i<=m;++i){ rd(op);scanf("%s",s+1); if(op==1)f.ins(s); else if(op==2)d.ins(s); else { printf("%d\n",f.query(s)-d.query(s)); } fflush(stdout); } return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* Date: 2019/2/24 15:19:38 */
二进制分组,对于许多插入删除根本不虚,反正暴力重构删除,O(nlogn)
(当然如果贡献不独立,还是cdq或者线段树分治吧,,)