【CF587F】Duff is Mad AC自动机+分块
【CF587F】Duff is Mad
题意:给出n个串$s_1,s_2..s_n$,有q组询问,每次给出l,r,k,问你编号在[l,r]中的所有串在$s_k$中出现了多少次。
$\sum|s_i|,q\le 10^5$
题解:先将询问离线,改成前缀相减。然后建出AC自动机,考虑分块。
对于长度$>\sqrt n$的询问串,这种串最多$\sqrt n$个,我们每次可以扫一遍整个fail树,处理出每个节点到根的路径上有多少个询问串中的点。然后将所有串一个一个加入到fail树里,假如加入的串的结束节点到根路径上有a个询问串种的点,则答案+=a。
对于长度$<\sqrt n$的串,我们按编号一个一个处理。我们加入一个串时,要将其结束节点的fail树子树中所有节点的点权都+1。放到DFS序上就是区间+操作。我们再次分块便可做到$O(1)-O(\sqrt n)$的复杂度。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <cmath> using namespace std; const int maxn=100010; typedef long long ll; int n,m,B,tot,cnt; ll sum; struct node { int ch[26],fail; }p[maxn]; struct query { int x,k,org; query() {} query(int a,int b,int c) {x=a,k=b,org=c;} }; int lp[maxn],rp[maxn],q[maxn],pos[maxn],head[maxn],to[maxn],nxt[maxn],p1[maxn],p2[maxn]; ll ans[maxn],s[maxn],sb[1000]; char str[maxn]; vector<query> v1[maxn],v2[maxn]; vector<query>::iterator it; inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();} while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar(); return ret*f; } inline void build() { int i,u,h=1,t=0; q[++t]=1; while(h<=t) { u=q[h++]; for(i=0;i<26;i++) { if(p[u].ch[i]) { q[++t]=p[u].ch[i]; if(u==1) p[p[u].ch[i]].fail=1; else p[p[u].ch[i]].fail=p[p[u].fail].ch[i]; } else { if(u==1) p[u].ch[i]=1; else p[u].ch[i]=p[p[u].fail].ch[i]; } } } } bool cmp(const query &a,const query &b) { return a.x<b.x; } inline void add(int a,int b) { to[cnt]=b,nxt[cnt]=head[a],head[a]=cnt++; } void dfs(int x) { p1[x]=++p2[0]; for(int i=head[x];i!=-1;i=nxt[i]) dfs(to[i]); p2[x]=p2[0]; } inline void upd(int a,int b) { int i,c=a/B,d=b/B; if(c==d) for(i=a;i<=b;i++) s[i]++; else { for(i=a;i<c*B+B;i++) s[i]++; for(i=d*B;i<=b;i++) s[i]++; for(i=c+1;i<d;i++) sb[i]++; } } int main() { n=rd(),m=rd(); int i,j,u,a,b,c; tot=1; for(i=1;i<=n;i++) { lp[i]=rp[i-1],scanf("%s",str+lp[i]),rp[i]=lp[i]+strlen(str+lp[i]); for(u=1,j=lp[i];j<rp[i];j++) { a=str[j]-'a'; if(!p[u].ch[a]) p[u].ch[a]=++tot; u=p[u].ch[a]; } pos[i]=u; } build(),B=int(sqrt(double(tot+1))); for(i=1;i<=m;i++) { a=rd(),b=rd(),c=rd(); if(rp[c]-lp[c]>B) { if(a!=1) v2[c].push_back(query(a-1,-1,i)); v2[c].push_back(query(b,1,i)); } else { if(a!=1) v1[a-1].push_back(query(c,-1,i)); v1[b].push_back(query(c,1,i)); } } memset(head,-1,sizeof(head)); for(i=2;i<=tot;i++) add(p[i].fail,i); dfs(1); for(i=1;i<=n;i++) { upd(p1[pos[i]],p2[pos[i]]); for(it=v1[i].begin();it!=v1[i].end();it++) { a=(*it).x,b=(*it).k,c=(*it).org; for(u=1,j=lp[a];j<rp[a];j++) { u=p[u].ch[str[j]-'a']; ans[c]+=(s[p1[u]]+sb[p1[u]/B])*b; } } } for(i=1;i<=n;i++) if(rp[i]-lp[i]>B&&v2[i].size()) { memset(s,0,sizeof(s)); for(u=1,j=lp[i];j<rp[i];j++) u=p[u].ch[str[j]-'a'],s[u]++; for(j=tot;j>=2;j--) s[p[q[j]].fail]+=s[q[j]]; sort(v2[i].begin(),v2[i].end(),cmp); for(sum=0,j=1,it=v2[i].begin();it!=v2[i].end();it++) { a=(*it).x,b=(*it).k,c=(*it).org; while(j<=a) sum+=s[pos[j++]]; ans[c]+=b*sum; } } for(i=1;i<=m;i++) printf("%lld\n",ans[i]); return 0; }//
| 欢迎来原网站坐坐! >原文链接<