小样例拍了10min,没有错误
前面的帖子看过了
将s和t都插入广义SAM,然后线段树合并parent树里的t的颜色数和出现次数。然后查询找到广义SAM上s的子串所在的状态,然后在这里查线段树
#include<bits/stdc++.h>
#define for1(i,a,b) for( int i=(a);i<=(b);i++)
#define for2(i,a,b) for( int i=(a);i<(b);i++)
#define for3(i,a,b) for( int i=(a);i>=(b);i--)
#define for4(i,a,b) for( int i=(a);i>(b);i--)
#define puba push_back
#define mem(a,b) memset((a),(b),sizeof((a)))
using namespace std;
int n,cnt,b[1100005],c[500005],T,l,r,x,y;
int son[1100005][26];
string s,t[50005];
void insert(string s){
int n=s.size(),u=1;
for2(i,0,n){
int c=s[i]-'a';
if(!son[u][c]) son[u][c]=++cnt;
u=son[u][c];
}
}
struct node{
int maxx,id;
}d[1100005*25];
struct segment{
int ll[1100005*25],rr[1100005*25],cnt;
node merge(node x,node y){
if(x.maxx<y.maxx) return y;
return x;
}
void push_up(int p){
d[p]=merge(d[ll[p]],d[rr[p]]);
}
void update(int l,int r,int &p,int s){
if(!p) p=++cnt;
if(l==r){
d[p].maxx=1;
d[p].id=l;
// cout<<l<<"-"<<p<<"\n";
return;
}
int mid=(l+r)>>1;
if(s<=mid) update(l,mid,ll[p],s);
else update(mid+1,r,rr[p],s);
push_up(p);
}
void merge(int l,int r,int p1,int p2){
if(l==r){
d[p1].maxx+=d[p2].maxx;
d[p1].id=l;
return;
}
int mid=(l+r)>>1;
if(ll[p1]&&ll[p2]) merge(l,mid,ll[p1],ll[p2]);
else if(ll[p2]) ll[p1]=ll[p2];
if(rr[p1]&&rr[p2]) merge(mid+1,r,rr[p1],rr[p2]);
else if(rr[p2]) rr[p1]=rr[p2];
push_up(p1);
}
node getsum(int l,int r,int p,int s,int t){
if(!p) return {0,0};
if(l>=s&&r<=t) return d[p];
int mid=(l+r)>>1;
node ans={0,0};
if(s<=mid) ans=merge(ans,getsum(l,mid,ll[p],s,t));
if(t>mid) ans=merge(ans,getsum(mid+1,r,rr[p],s,t));
return ans;
}
void print(int l,int r,int p){
if(!p) return;
if(l==r){
cout<<l<<"-"<<d[p].maxx<<" "<<p<<"\n";
return;
}
int mid=(l+r)>>1;
print(l,mid,ll[p]);
print(mid+1,r,rr[p]);
}
}seg;
struct gsam{
int cnt,pos[1100005],h[1100005][22],pos1[500005];
struct node{
int nxt[26],link,len;
}st[1100005];
void insert(int c,int &lst){
int cur=++cnt,p=lst;
st[cur].len=st[lst].len+1;
lst=cur;
while(p&&!st[p].nxt[c]){
st[p].nxt[c]=cur;
p=st[p].link;
}
if(!p){
st[cur].link=1;
return;
}
int q=st[p].nxt[c];
if(st[p].len+1==st[q].len){
st[cur].link=q;
return;
}
int clone=++cnt;
st[clone]=st[q];
st[clone].len=st[p].len+1;
st[cur].link=st[q].link=clone;
while(p&&st[p].nxt[c]==q){
st[p].nxt[c]=clone;
p=st[p].link;
}
}
void bfs(){
queue<int>q;
q.push(1);
pos[1]=1;
while(!q.empty()){
int u=q.front();
q.pop();
for2(i,0,26){
int to=son[u][i];
if(!to) continue;
pos[to]=pos[u];
insert(i,pos[to]);
q.push(to);
}
}
}
void build(){
for1(i,1,cnt) h[i][0]=st[i].link;
for1(j,1,21)
for1(i,1,cnt)
h[i][j]=h[h[i][j-1]][j-1];
for1(i,1,cnt) c[st[i].len]++;
for1(i,1,5e5) c[i]+=c[i-1];
for1(i,1,cnt) b[c[st[i].len]--]=i;
for3(i,cnt,2){
int u=st[b[i]].link,to=b[i];
// cout<<u<<" "<<to<<"\n";
// cout<<n<<"\n";
seg.merge(1,n,u,to);
}
}
void upd(string s,int id){
int len=s.size(),u=1;
for2(i,0,len){
u=son[u][s[i]-'a'];
// cout<<pos[u]<<":"<<id<<"\n";
seg.update(1,n,pos[u],id);
// seg.print(1,n,pos[u]);
}
// for1(i,1,cnt){
// // cout<<id<<"\n";
// // cout<<1<<"\n";
// seg.print(1,3,i);
// }
}
void pre(){
int u=1,n=s.size();
for2(i,0,n){
u=son[u][s[i]-'a'];
pos1[i]=pos[u];
}
}
int get(int l,int r){
int u=pos1[r-1];
for3(i,21,0)
if(st[h[u][i]].len>=(r-l+1)) u=h[u][i];
return u;
}
}sam;
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
// freopen("make.in","r",stdin);
// freopen("my.out","w",stdout);
sam.cnt=cnt=1;
cin>>s;
insert(s);
cin>>n;
for1(i,1,n) cin>>t[i],insert(t[i]);
sam.bfs();
seg.cnt=sam.cnt;
sam.pre();
for1(i,1,n){
sam.upd(t[i],i);
}
sam.build();
// seg.print(1,3,11);
cin>>T;
while(T--){
cin>>l>>r>>x>>y;
int u=sam.get(x,y);
// cout<<u<<"\n";
node ans=seg.getsum(1,n,u,l,r);
if(ans.maxx==0) cout<<l<<" "<<0<<"\n";
else cout<<ans.id<<" "<<ans.maxx<<"\n";
}
// cout<<1;
return 0;
}