【CF587F】Duff is Mad AC自動機+分塊
阿新 • • 發佈:2018-03-31
query tor 題解 upd AR div -o OS iter
【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; }//
【CF587F】Duff is Mad AC自動機+分塊