Codeforces, 587F: Duff is Mad

xiaoxiao2021-02-27  364

Duff is Mad

给出 n 个字符串S1,S2......Sn q 个询问。 每次询问给定l,r,k, 要求输出 ri=loccur(Si,Sk) ,. 其中 occur(S,T) 表示 S T中出现的次数。 n,q,ni=1|Si|105

Solution

考虑建立AC自动机, fail 指针形成了一棵 par 树。令 End(i) 表示第 i 个字符串对应的结束结点。对于询问(l,r,k) 其实就是把从 root End(i) 上的所有节点以及他们在 par 树 上的祖先结点里面 SlSr 的结束结点的个数。对于 length(x)>n 的字符串 Sx ,单独DFS一遍,求出 cnt(i) 表示第 End(i) 出现了几次,求 cnt 的前缀和就可以 O(1) 回答 k=x 的询问。对于 length(x)n 的字符串 Sx ,在 root End(x) 上的所有节点的相关结点集合中加入 x <script type="math/tex" id="MathJax-Element-3863">x</script>.DFS整棵树,给所有相关集合中的点的询问加上贡献。需要动态维护前缀和。注意到询问次数比较多,用分块维护。

Code

#include<cstdio> #include<iostream> #include<cstdlib> #include<cstring> #include<cmath> #include<vector> #include<queue> #define LL long long #define CLEAR(xxx) memset(xxx,0,sizeof(xxx)) using namespace std; const int maxn=150000; char s[maxn]; int n,qq,tot=1,lim; int Root=1,len[maxn],End[maxn]; vector<int> word[maxn]; vector<int> sons[maxn]; vector<int> A[maxn]; LL ans[maxn]; struct node{ int Next[26],fa,fail; }T[maxn]; struct Ask{ int L,R,id; Ask(){} Ask(int L,int R,int id):L(L),R(R),id(id){} }; vector<Ask> Q[maxn]; queue<int> q; void Build_AC_Automaton(){ q.push(Root); int i,j; while(!q.empty()){ int x= q.front(); q.pop(); for(i=0;i<26;i++) if(T[x].Next[i]){ int v= T[x].Next[i]; for(j=T[x].fail;j && !T[j].Next[i]; j=T[j].fail); T[v].fail= j? T[j].Next[i]:Root; q.push(v); } } } LL sum[maxn],f[maxn]; void dfs(int x){ int i; for(i=0;i<sons[x].size();i++){ dfs(sons[x][i]); f[x]+=f[sons[x][i]]; } for(i=0;i<word[x].size();i++) sum[word[x][i]]+=f[x]; } void SolveLongWords(){ int i,j; for(i=1;i<=n;i++) if(len[i]>lim){ CLEAR(sum); CLEAR(f); for(j=End[i];j;j=T[j].fa) f[j]=1; dfs(1); for(j=1;j<=n;j++) sum[j]+=sum[j-1]; for(j=0;j<Q[i].size();j++) ans[Q[i][j].id] = sum[Q[i][j].R]-sum[Q[i][j].L-1]; } } LL Sum[maxn],delta[maxn]; int id[maxn]; void Add(int x,int d){ for(int i=x;id[i]==id[x];i++) Sum[i]+=d; for(int i=id[x]+1;i<=id[n];i++) delta[i]+=d; } LL Query(int x){ return Sum[x]+delta[id[x]]; } void DFS(int x){ int i,j; for(i=0;i<word[x].size();i++) Add(word[x][i],1); for(i=0;i<A[x].size();i++){ int o = A[x][i]; for(j=0;j<Q[o].size();j++){ Ask t= Q[o][j]; ans[t.id]+=Query(t.R)-Query(t.L-1); } } for(i=0;i<sons[x].size();i++) DFS(sons[x][i]); for(i=0;i<word[x].size();i++) Add(word[x][i],-1); } int main(){ int i,j,k,x,y; scanf("%d%d",&n,&qq); lim= (int)sqrt(n); for(i=1;i<=n;i++) id[i]=(i-1)/lim+1; for(i=1;i<=n;i++){ scanf("%s",s+1); len[i]= strlen(s+1); int cur= Root; for(j=1;j<=len[i];j++){ int c= s[j]-'a'; if(!T[cur].Next[c]) T[cur].Next[c]= ++tot,T[tot].fa=cur; cur= T[cur].Next[c]; if(len[i]<=lim) A[cur].push_back(i); } End[i] = cur; word[cur].push_back(i); } Build_AC_Automaton(); for(i=1;i<=tot;i++) sons[T[i].fail].push_back(i); //建 par 树 for(i=1;i<=qq;i++){ scanf("%d%d%d",&x,&y,&k); Q[k].push_back(Ask(x,y,i)); } SolveLongWords(); DFS(1); for(i=1;i<=qq;i++) printf("%I64d\n",ans[i]); return 0; }
转载请注明原文地址: https://www.6miu.com/read-3583.html

最新回复(0)