實力強大的小A 被選爲了ION2018 的出題人,如今他須要解決題目的命名問題。html
小A 被選爲了ION2018 的出題人,他精心準備了一道質量十分高的題目,且已經把除了題目命名之外的工做都作好了。node
因爲ION 已經舉辦了不少屆,因此在題目命名上也是有規定的,ION 命題手冊規定:每一年由命題委員會規定一個小寫字母字符串,咱們稱之爲那一年的命名串,要求每道題的名字必須是那一年的命名串的一個非空連續子串,且不能和前一年的任何一道題目的名字相同。數組
因爲一些特殊的緣由,小A 不知道ION2017 每道題的名字,可是他經過一些特殊手段獲得了ION2017 的命名串,如今小A 有Q 次詢問:每次給定ION2017 的命名串和ION2018 的命名串,求有幾種題目的命名,使得這個名字必定知足命題委員會的規定,便是ION2018 的命名串的一個非空連續子串且必定不會和ION2017 的任何一道題目的名字相同。ide
因爲一些特殊緣由,全部詢問給出的ION2017 的命名串都是某個串的連續子串,詳細可見輸入格式。ui
第一行一個字符串S ,以後詢問給出的ION2017 的命名串都是S 的連續子串。 第二行一個正整數Q,表示詢問次數。 接下來Q 行,每行有一個字符串T 和兩個正整數l,rl,r,表示詢問若是ION2017 的 命名串是S [l..r]S[l..r],ION2018 的命名串是T 的話,有幾種命名方式必定知足規定。spa
輸出Q 行,第i 行一個非負整數表示第i 個詢問的答案。指針
1 scbamgepe 2 3 3 smape 2 7 4 sbape 3 8 5 sgepe 1 9
1 12 2 10 3 4
咱們考慮對於一個詢問,先求出TT中本質不一樣的子串個數,而後減去是S(l,r)S(l,r)子串的。code
本質不一樣的子串個數,直接用height數組的性質就能夠求。htm
咱們考慮,對於TT的每個後綴,求出其最長的前綴長度LL,使得該後綴長度爲LL的前綴是S(l,r)S(l,r)的子串。blog
把SS和全部TT連起來建後綴數組。爲了方便計算每一個詢問,咱們用鏈表的方法,記錄每一個位置在同一個串中的前驅後繼。
而後咱們按順序考慮TT的每個後綴。
若是aa位置的後綴的知足條件的最長前綴爲LL,,則a+1a+1位置的至少爲L-1L−1。原理和求height數組相同,兩邊都同時去掉第一個字符,至少還留下L-1L−1。
因此考慮每一個位置的話,用雙指針掃描一下便可。
而後,假如咱們如今考慮位置aa的長度爲LL的前綴是否可行,就是至關於在SS的[l,r-L+1][l,r−L+1]內找一個位置bb,知足LCP(a,b)\geqslant LLCP(a,b)⩾L。
知足LCP(a,b)\geqslant LLCP(a,b)⩾L條件的在後綴數組上的區間[ll,rr][ll,rr],能夠二分,配合height數組的ST表在O(\log n)O(logn)的時間內求出。
而後問題轉化爲詢問在後綴數組上的區間[ll,rr][ll,rr]內,是否存在一個在SS的[l,r-l+1][l,r−l+1]中的字符。這個問題能夠用建主席樹而後詢問,單次查詢時間複雜度O(\log n)O(logn)。
對於一個位置,它與後綴數組上一個位置可能會算重,因此要減掉它們的LCPLCP。因爲兩個位置可能不連續,這部分也要用ST表來查。
因此總時間複雜度O(n\log n)O(nlogn)。n=|S|+\sum|T|n=∣S∣+∑∣T∣。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define N 500505 5 #define M 1800505 6 #define reg register 7 #define lg2(x)(31-__builtin_clz(x)) 8 typedef long long LL; 9 int n,sa[M],height[M],x[M],s[M],mgk,bel[M],m,QL[N],QR[N],y[M],st[22][M],nxt[M],head[N],node=0,rt[M],pp[M],len[N]; 10 int ls[M*20],rs[M*20],sz[M*20]; 11 char ss[N]; 12 bool isk; 13 int _L,_R; 14 void add(int&o,int pr,int l,int r,int pos){ 15 sz[o=++node]=sz[pr]+1; 16 if(l<r){ 17 const int mid=l+r>>1; 18 if(pos<=mid)add(ls[o],ls[pr],l,mid,pos),rs[o]=rs[pr];else add(rs[o],rs[pr],mid+1,r,pos),ls[o]=ls[pr]; 19 } 20 } 21 void sort(){ 22 int m=mgk,c[M]; 23 for(int i=1;i<=m;++i)c[i]=0; 24 for(int i=1;i<=n;++i)++c[x[i]=s[i]]; 25 for(int i=1;i<=m;++i)c[i]+=c[i-1]; 26 for(int i=n;i;--i)sa[c[x[i]]--]=i; 27 for(int k=1,p;k<=n;k<<=1){ 28 p=0; 29 for(int i=n-k+1;i<=n;++i)y[++p]=i; 30 for(reg int i=1;i<=n;++i)if(sa[i]>k)y[++p]=sa[i]-k; 31 for(reg int i=1;i<=m;++i)c[i]=0; 32 for(reg int i=1;i<=n;++i)++c[x[i]]; 33 for(reg int i=1;i<=m;++i)c[i]+=c[i-1]; 34 for(reg int i=n;i;--i)sa[c[x[y[i]]]--]=y[i]; 35 std::swap(x,y); 36 x[sa[1]]=p=1; 37 for(int i=2;i<=n;++i) 38 x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p:++p; 39 if(p==n)break; 40 m=p; 41 } 42 for(int i=1,k=0;i<=n;++i) 43 if(x[i]>1){ 44 k-=!!k; 45 const int j=sa[x[i]-1]; 46 while(s[i+k]==s[j+k])++k; 47 height[x[i]]=k; 48 } 49 } 50 inline int find(int l,int r){ 51 if(l>r)return n; 52 const int lg=lg2(r-l+1); 53 return std::min(st[lg][l],st[lg][r-(1<<lg)+1]); 54 } 55 void init(){ 56 for(reg int i=1;i<=n;++i)st[0][i]=height[i]; 57 for(int i=0;i<21;++i) 58 for(reg int j=1;j<=n;++j) 59 if(j+(1<<i)<=n)st[i+1][j]=std::min(st[i][j],st[i][j+(1<<i)]);else break; 60 int pre[N]; 61 memset(pre,0,sizeof pre); 62 for(int i=1;i<=n;++i) 63 if(s[sa[i]]<='z'){ 64 if(pre[bel[sa[i]]]) 65 nxt[pre[bel[sa[i]]]]=i,pp[i]=pre[bel[sa[i]]];else head[bel[sa[i]]]=i; 66 pre[bel[sa[i]]]=i; 67 } 68 } 69 void query(const int&ri,const int&le,int l,int r){ 70 if(sz[ri]==sz[le]||isk)return; 71 if(_L<=l&&r<=_R)return(void)(isk=1); 72 const int mid=l+r>>1; 73 if(_L<=mid)query(ls[ri],ls[le],l,mid); 74 if(mid<_R&&!isk)query(rs[ri],rs[le],mid+1,r); 75 } 76 bool check(int pos,int len,int l,int r){ 77 int L,ll,rr; 78 ll=1,rr=pos-1; 79 while(ll<=rr){ 80 const int mid=ll+rr>>1; 81 if(find(mid+1,pos)>=len)rr=mid-1;else ll=mid+1; 82 } 83 L=rr; 84 ll=pos+1,rr=n; 85 while(ll<=rr){ 86 const int mid=ll+rr>>1; 87 if(find(pos+1,mid)>=len)ll=mid+1;else rr=mid-1; 88 } 89 isk=0; 90 _L=l,_R=r; 91 query(rt[ll-1],rt[L],1,n); 92 return isk; 93 } 94 int main(){ 95 memset(bel,-1,sizeof bel); 96 mgk='z'+1; 97 scanf("%s",ss); 98 for(int i=0;ss[i];++i) 99 s[++n]=ss[i],bel[n]=0; 100 s[++n]=mgk++; 101 scanf("%d",&m); 102 for(int i=1;i<=m;++i){ 103 scanf("%s%d%d",ss,QL+i,QR+i); 104 for(int j=0;ss[j];++j) 105 s[++n]=ss[j],bel[n]=i; 106 len[i]=n; 107 s[++n]=mgk++; 108 } 109 sort(); 110 init(); 111 for(reg int i=1;i<=n;++i) 112 if(!bel[sa[i]])add(rt[i],rt[i-1],1,n,sa[i]);else rt[i]=rt[i-1]; 113 for(int i=1;i<=m;++i){ 114 LL ans=len[i]-sa[head[i]]+1; 115 int mnid=sa[head[i]]; 116 for(int j=nxt[head[i]];j;j=nxt[j]){ 117 ans+=len[i]-sa[j]+1; 118 ans-=find(pp[j]+1,j); 119 mnid=std::min(mnid,sa[j]); 120 } 121 for(int j=mnid,L=mnid;s[j]<='z';++j){ 122 if(L<j)L=j; 123 while(s[L]<='z'&&check(x[j],L-j+1,QL[i],QR[i]-L+j))++L; 124 if(x[j]!=head[i])ans-=std::max(L-j-find(pp[x[j]]+1,x[j]),0);else 125 ans-=L-j; 126 } 127 printf("%lld\n",ans); 128 } 129 return 0; 130 }