codeforces #305 E Mike and friends
原问题可以转化为:给定第k个字符串,求它在L-R的字符串里作为子串出现了多少次
定义子串为字符串的某个前缀的某个后缀(废话)
等价于我们把一个字符串插入到trie里,其过程中每个经过的节点和其向上的fail链上的点都是该字符串的子串
又因为对于一条fail链,u向上能访问到v当前仅当u在v的子树内
那么原问题又变成了:
将L-R个字符串按照上述方法插入到trie中并将经过的节点的val值增加
求第k个字符串对应的单词节点在fail树上的子树的权值和
又因为查询的信息满足区间可减性,所以我们可以建出fail树
对fail树用可持久化线段树维护DFS序 完成单点修改和子树查询
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #include<queue> using namespace std; const int maxn=500010; int n,m,sum=0; int L,R,k; int pos[maxn]; int rt[maxn]; char s[maxn]; queue<int>Q; int h[maxn],cnt=0; int A[maxn],B[maxn],tot=0; struct edge{ int to,next; }G[maxn<<1]; void add(int x,int y){++cnt;G[cnt].to=y;G[cnt].next=h[x];h[x]=cnt;} void Get_DFS(int u){ A[u]=++tot; for(int i=h[u];i;i=G[i].next)Get_DFS(G[i].to); B[u]=tot; } struct Seg_Tree{ int L,R,v; }t[11000010]; void build(int &o,int L,int R){ o=++sum; if(L==R)return; int mid=(L+R)>>1; build(t[o].L,L,mid); build(t[o].R,mid+1,R); } void modify(int &o,int L,int R,int p){ t[++sum]=t[o];o=sum; if(L==R){t[o].v++;return;} int mid=(L+R)>>1; if(p<=mid)modify(t[o].L,L,mid,p); else modify(t[o].R,mid+1,R,p); t[o].v=t[t[o].L].v+t[t[o].R].v; } int ask(int o,int L,int R,int x,int y){ if(L>=x&&R<=y)return t[o].v; int mid=(L+R)>>1; if(y<=mid)return ask(t[o].L,L,mid,x,y); else if(x>mid)return ask(t[o].R,mid+1,R,x,y); else return ask(t[o].L,L,mid,x,y)+ask(t[o].R,mid+1,R,x,y); } struct Trie{ int cnt; int t[maxn][26]; int fail[maxn],fa[maxn]; void init(){ cnt=1;fail[0]=1; for(int i=0;i<26;++i)t[0][i]=1; } int insert(){ int len=strlen(s+1); int now=1; for(int i=1;i<=len;++i){ int id=s[i]-'a'; if(!t[now][id])t[now][id]=++cnt,fa[t[now][id]]=now; now=t[now][id]; }return now; } void build_fail(){ Q.push(1);fail[1]=0; while(!Q.empty()){ int u=Q.front();Q.pop(); for(int i=0;i<26;++i){ if(t[u][i]){ int k=fail[u]; while(!t[k][i])k=fail[k]; fail[t[u][i]]=t[k][i]; add(t[k][i],t[u][i]); Q.push(t[u][i]); } } }return; } void UPD(){ build(rt[0],1,cnt); for(int i=1;i<=n;++i){ rt[i]=rt[i-1]; for(int j=pos[i];j!=1;j=fa[j]){ modify(rt[i],1,cnt,A[j]); } }return; } }AC; int main(){ scanf("%d%d",&n,&m); AC.init(); for(int i=1;i<=n;++i){ scanf("%s",s+1); pos[i]=AC.insert(); }AC.build_fail();Get_DFS(1);AC.UPD(); for(int i=1;i<=m;++i){ scanf("%d%d%d",&L,&R,&k); printf("%d\n",ask(rt[R],1,AC.cnt,A[pos[k]],B[pos[k]])-ask(rt[L-1],1,AC.cnt,A[pos[k]],B[pos[k]])); }return 0; }
即可