CF587F Duff is Mad(AC自動機+樹狀數組+分塊)
阿新 • • 發佈:2019-01-08
復雜 amp pop space str 分塊 clu ostream \n 預處理\(O(1)\)查詢。復雜度\(O(nL)\)無法通過此題。
然後我們對詢問分塊。長度大於\(sqrt(L)\)的用方法二,其他的用方法一。這樣方法二最多用\(\sqrt{n}\)次。復雜度\(O(\sqrt{n}L)\)。方法一因為麽次詢問的串長最多為\(\sqrt{L}\),所以復雜度為\(O(m\sqrt{L}logL)\)最終復雜度就是這兩個加起來。可以通過此題。
考慮兩一個暴力
1
因為詢問\([a,b]\)可以拆成\([1,b]\)-\([1,a-1]\)所以把詢問離線,然後就是求\([1,x]\)中被\(S_i\)包含的串的數量。考慮當\([1,x-1]->[1,x]\)時我們把\(S_x\)結束節點在fail樹的子樹加1。然後詢問就是求\(S_i\)在AC自動機上跑時經過所有點的點權用樹狀數組維護。設\(\sum{len[S_i]}=L\)這樣的復雜度就是\(O(mLlogL)\)無法通過此題。
2
依然離線。這次我們把\(S_i\)放在fail樹上跑時經過的點在fail樹上加1。然後每一個x的貢獻就是x的子樹和。這個我們在fail樹上DP(合並size)再做一個前綴合就能做到\(O(n)\)
然後我們對詢問分塊。長度大於\(sqrt(L)\)的用方法二,其他的用方法一。這樣方法二最多用\(\sqrt{n}\)次。復雜度\(O(\sqrt{n}L)\)。方法一因為麽次詢問的串長最多為\(\sqrt{L}\),所以復雜度為\(O(m\sqrt{L}logL)\)最終復雜度就是這兩個加起來。可以通過此題。
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<algorithm> #include<queue> #include<vector> using namespace std; const int N=201000; const int M=501000; int cnt,head[N]; int n,m; long long ans[M]; int dfn[N],R[N],L[N],tot,LEN; long long tr[N]; long long size[N],sum[N]; string s[N]; struct ques{ int x,k,id; ques(int xx=0,int kk=0,int idd=0){ x=xx;k=kk;id=idd; } }; vector<ques> vec1[N],vec2[N]; struct edge{ int to,nxt; }e[N]; void add_edge(int u,int v){ cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt; } int lowbit(int x){ return x&-x; } void add(int x,int w){ for(int i=x;i<=tot;i+=lowbit(i))tr[i]+=w; } long long getsum(int x){ long long tmp=0; for(int i=x;i;i-=lowbit(i))tmp+=tr[i]; return tmp; } void dfs(int u){ dfn[u]=++tot; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to; dfs(v); } R[u]=tot; } void dfs1(int u){ for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to; dfs1(v); size[u]+=size[v]; } } struct AC{ int point[N],trans[N][27],tot,fail[N]; void ins(string s,int len,int k){ int now=0; for(int i=0;i<len;i++){ if(trans[now][s[i]-'a'+1]==0)trans[now][s[i]-'a'+1]=++tot; now=trans[now][s[i]-'a'+1]; } point[k]=now; } void get_fail(){ queue<int> q; for(int i=1;i<=26;i++)if(trans[0][i])q.push(trans[0][i]); while(!q.empty()){ int now=q.front(); q.pop(); for(int i=1;i<=26;i++){ if(trans[now][i])fail[trans[now][i]]=trans[fail[now]][i],q.push(trans[now][i]); else trans[now][i]=trans[fail[now]][i]; } } } }ac; int read(){ int sum=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();} return sum*f; } int main(){ n=read();m=read(); for(int i=1;i<=n;i++){ cin>>s[i]; L[i]=s[i].size(); LEN+=L[i]; ac.ins(s[i],L[i],i); } int hhh=getchar(); int block=sqrt(LEN); ac.get_fail(); for(int i=1;i<=ac.tot;i++)add_edge(ac.fail[i],i); dfs(0); for(int i=1;i<=m;i++){ int a=read(),b=read(),c=read(); if(L[c]>block){ vec1[c].push_back(ques(b,1,i)),vec1[c].push_back(ques(a-1,-1,i)); } else vec2[a-1].push_back(ques(c,-1,i)),vec2[b].push_back(ques(c,1,i)); } for(int i=1;i<=n;i++){ int now=0; for(int j=0;j<L[i];j++){ now=ac.trans[now][s[i][j]-'a'+1]; if(j==L[i]-1)add(dfn[now],1),add(R[now]+1,-1); } for(int j=0;j<vec2[i].size();j++){ int now=0; for(int k=0;k<L[vec2[i][j].x];k++){ now=ac.trans[now][s[vec2[i][j].x][k]-'a'+1]; ans[vec2[i][j].id]+=(long long)vec2[i][j].k*getsum(dfn[now]); } } if(vec1[i].size()){ for(int j=0;j<=tot;j++)size[j]=sum[j]=0; int now=0; for(int j=0;j<L[i];j++)now=ac.trans[now][s[i][j]-'a'+1],size[now]++; dfs1(0); for(int j=1;j<=n;j++)sum[j]=sum[j-1]+size[ac.point[j]]; for(int j=0;j<vec1[i].size();j++) ans[vec1[i][j].id]+=(long long)vec1[i][j].k*sum[vec1[i][j].x]; } } for(int i=1;i<=m;i++)printf("%lld\n",ans[i]); return 0; }
CF587F Duff is Mad(AC自動機+樹狀數組+分塊)