传送门
题解:
反正空间有1.22个G,xjb乱开也不会MLE
题意简述:
给你一个串 S S S,每次询问给出串 T T T 和区间 l , r l,r l,r,请你回答 T T T有多少个本质不同的子串没有在 S [ l : r ] S[l:r] S[l:r] 中出现。
我们如果能够求出 T T T 每个前缀在 S [ l : r ] S[l:r] S[l:r] 中的最长匹配长度问题就解决了。
首先考虑 l = 1 , r = ∣ S ∣ l=1,r=|S| l=1,r=∣S∣ 的情况,对 S S S 建立SAM,把 T T T 放上去跑,得到 T T T 每一个前缀的最长匹配长度,对 T T T 建立SAM,每个节点代表的串的最长的能够在 S S S 中匹配的长度就是 r i g h t right right 集合中随便一个点的前缀在 S S S中的最长出现长度,在SAM上把答案算出来就行了。
现在考虑 l , r l,r l,r 任意的情况,现在我们需要求出 T T T 的每个前缀在 S [ l : r ] S[l:r] S[l:r] 的最长出现后缀长度。问题其实就是是否匹配位置的 r i g h t right right 集合中有一个能够完全放到 S [ l : r ] S[l:r] S[l:r] 中,线段树合并维护一下 r i g h t right right 集合,失配的时候暴力将匹配长度 − 1 -1 −1 然后看能不能跳到父亲,复杂度是对的。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
using std::cerr;
using std::cout;
cs int N=1e6+7;
int n,m;
char s[N];int len;
namespace SGT{
cs int N=::N*40;
int lc[N],rc[N],tot;
inline int _copy(int u){++tot;lc[tot]=lc[u],rc[tot]=rc[u];return tot;}
inline void ins(int &u,int l,int r,int p){
u=++tot;if(l==r)return ;int mid=l+r>>1;
(p<=mid)?ins(lc[u],l,mid,p):ins(rc[u],mid+1,r,p);
}
inline void merge(int &u,int v){
if(!u||!v){u|=v;return ;}u=_copy(u);
merge(lc[u],lc[v]);
merge(rc[u],rc[v]);
}
inline bool query(int u,int l,int r,int ql,int qr){
if(!u||qr<l||r<ql)return false;
if(ql<=l&&r<=qr)return true;int mid=l+r>>1;
return query(lc[u],l,mid,ql,qr)||query(rc[u],mid+1,r,ql,qr);
}
}
namespace S{
cs int N=::N<<1|1;
int son[N][26],fa[N],len[N],now,root;
inline void init(int n){root=now=n+1;}
inline void push_back(int i,int c){
int cur=i,p=(i-1)?(i-1):root;
len[cur]=len[p]+1;
for(;p&&!son[p][c];p=fa[p])son[p][c]=cur;
if(!p)fa[cur]=root;
else if(len[son[p][c]]==len[p]+1)fa[cur]=son[p][c];
else {
int nq=++now,q=son[p][c];
memcpy(son[nq],son[q],sizeof son[q]);
len[nq]=len[p]+1;fa[nq]=fa[q];
fa[q]=fa[cur]=nq;
for(;p&&son[p][c]==q;p=fa[p])son[p][c]=nq;
}
}
int bin[N],nd[N],rt[N];
inline void build(){
for(int re i=1;i<=now;++i)++bin[len[i]];
for(int re i=1;i<=n;++i)bin[i]+=bin[i-1];
for(int re i=1;i<=now;++i)nd[bin[len[i]]--]=i;
for(int re i=1;i<=n;++i)SGT::ins(rt[i],1,n,i);
for(int re i=now;i>1;--i){int u=nd[i];SGT::merge(rt[fa[u]],rt[u]);}
}
inline void match(int &u,int &nl,cs int l,cs int r,cs int c){
while(true){
if(son[u][c]&&SGT::query(rt[son[u][c]],1,n,l+nl,r)){
++nl;u=son[u][c];return ;
}
if(!nl)return ;
if(--nl==len[fa[u]])u=fa[u];
}
}
}
int vl[N];
namespace T{
cs int N=::N<<1|1;
int son[N][26],fa[N],len[N],ps[N],now,root;
inline void clear(){
memset(son,0,sizeof(int)*(now+1)*26);
}
inline void init(int n){root=now=n+1;fa[root]=len[root]=0;}
inline void push_back(int i,int c){
int cur=i,p=(i-1)?(i-1):root;
ps[cur]=len[cur]=len[p]+1;
for(;p&&!son[p][c];p=fa[p])son[p][c]=cur;
if(!p)fa[cur]=root;
else if(len[son[p][c]]==len[p]+1)fa[cur]=son[p][c];
else {
int nq=++now,q=son[p][c];
memcpy(son[nq],son[q],sizeof son[q]);
ps[nq]=ps[q];len[nq]=len[p]+1;
fa[nq]=fa[q];fa[q]=fa[cur]=nq;
for(;p&&son[p][c]==q;p=fa[p])son[p][c]=nq;
}
}
inline ll calc(){
ll ans=0;for(int re i=1;i<=now;++i)
ans+=std::max(0,len[i]-std::max(len[fa[i]],vl[ps[i]]));
return ans;
}
}
inline void solve(){
int l,r;scanf("%s%d%d",s+1,&l,&r);
len=strlen(s+1);T::clear();T::init(len);
int u=S::root;
for(int re i=1;i<=len;++i){
vl[i]=vl[i-1];
S::match(u,vl[i],l,r,s[i]-'a');
T::push_back(i,s[i]-'a');
}
cout<<T::calc()<<"\n";
}
signed main(){
#ifdef zxyoi
freopen("name.in","r",stdin);
#endif
scanf("%s",s+1);len=n=strlen(s+1);S::init(len);
for(int re i=1;i<=len;++i)S::push_back(i,s[i]-'a');
S::build();scanf("%d",&m);
while(m--)solve();
return 0;
}