题目链接:https://www.luogu.com.cn/problem/P2414
由于Fail指针指向 “这个串的最长后缀”。而指向的那个点又是某个字符串的前缀。所以后缀的前缀是子串。
然后可以直接建出Fail树,建树时,如果$'B'$,那么就返回到这个节点的父亲,如果$'P'$,就把这一组存下来,vis和id是互为映射。
一遍DFS,处理出DFS序,然后便可以进行区间操作了。
用离线处理的方法,把每一组按照y排序,那么可以处理每一组询问,把同一种询问保存在一起。
比如询问第1个打印的字符串在第3个出现了几次,询问第2个字符串在第3个出现了几次,就可以把两个询问合并,变成:第3个打印的字符串中出现了几次第1个,几个第2个。
然后考虑每一个的贡献,可以用树状数组维护,如果有一个小写字母,那么便区间+1,每'B'一次,则区间-1。每'P'一次,则区间询问一次,求出答案,并离线记录。
AC代码:
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<queue> 6 using namespace std; 7 const int N=1000000+10; 8 char str[N]; 9 int ch[N][26],fail[N],vis[N],fa[N]; 10 int cnt,num,dfn,tot; 11 int L[N],R[N],head[N],id[N],ans[N],c[N]; 12 struct node{ 13 int to,next; 14 }edge[N*2]; 15 struct Node{ 16 int x,y; 17 int pos; 18 }q[N]; 19 bool cmp(Node aa,Node bb){ 20 return aa.y<bb.y; 21 } 22 void init(){ 23 num=dfn=cnt=tot=0; 24 memset(vis,0,sizeof(vis)); 25 memset(head,-1,sizeof(head)); 26 } 27 void add(int u,int v){ 28 edge[tot].to=v; 29 edge[tot].next=head[u]; 30 head[u]=tot++; 31 } 32 void get_fail(){ 33 queue<int> q; 34 for(int i=0;i<26;i++){ 35 if(ch[0][i]){ 36 add(0,ch[0][i]); 37 q.push(ch[0][i]); 38 } 39 } 40 while(!q.empty()){ 41 int u=q.front();q.pop(); 42 for(int i=0;i<26;i++){ 43 if(ch[u][i]){ 44 fail[ch[u][i]]=ch[fail[u]][i]; 45 q.push(ch[u][i]); 46 add(fail[ch[u][i]],ch[u][i]); 47 } 48 else ch[u][i]=ch[fail[u]][i]; 49 } 50 } 51 } 52 void DFS(int u,int fa){ 53 L[u]=++dfn; 54 for(int i=head[u];i!=-1;i=edge[i].next){ 55 int v=edge[i].to; 56 if(v==fa) continue; 57 DFS(v,u); 58 } 59 R[u]=dfn; 60 } 61 int lowbit(int x){ 62 return x&(-x); 63 } 64 void addval(int x,int val){ 65 while(x<=dfn){ 66 c[x]+=val; 67 x+=lowbit(x); 68 } 69 } 70 int query(int x){ 71 int ans=0; 72 while(x){ 73 ans+=c[x]; 74 x-=lowbit(x); 75 } 76 return ans; 77 } 78 int main(){ 79 scanf("%s",str); 80 int len=strlen(str); 81 init(); 82 int u=0; 83 for(int i=0;i<len;i++){ 84 if(str[i]>='a'&&str[i]<='z'){ 85 int id=str[i]-'a'; 86 if(!ch[u][id]) ch[u][id]=++cnt; 87 fa[cnt]=u; 88 u=ch[u][id]; 89 } 90 else if(str[i]=='B') u=fa[u]; 91 else vis[u]=++num,id[num]=u; 92 } 93 get_fail(); 94 DFS(0,-1); 95 int n; 96 scanf("%d",&n); 97 for(int i=1;i<=n;i++){ 98 scanf("%d%d",&q[i].x,&q[i].y); 99 q[i].pos=i; 100 } 101 sort(q+1,q+n+1,cmp); 102 num=0; 103 int j=0,root=0; 104 for(int i=0;i<len;i++){ 105 if(str[i]=='B') addval(L[root],-1),root=fa[root]; 106 else if(str[i]=='P'){ 107 num++; 108 while(j<n&&q[j+1].y==num){ 109 j++; 110 int v=id[q[j].x]; 111 ans[q[j].pos]=query(R[v])-query(L[v]-1); 112 } 113 } 114 else{ 115 int id=str[i]-'a'; 116 root=ch[root][id]; 117 addval(L[root],1); 118 } 119 } 120 for(int i=1;i<=n;i++) printf("%d ",ans[i]); 121 return 0; 122 }