XVII.CF666E Forensic Examination
首先,同之前大部分题一样,本题仍然有两种解法。SA解法参见本人的题解。SAM解法见下。
仍然,同之前大部分题一样,本题SAM解法完爆SA——码量、思维难度、复杂度。
首先,考虑把所有东西怼一块跑广义SAM,然后对于询问的原串中某一段区间,可以直接在parent tree上倍增找到其对应的节点。
于是,我们现在就需要知道该节点的 \(\text{endpos}\) 集合中来自于 \([L,R]\) 的元素中出现最多的一类。无脑线段树合并即可。
时间复杂度 \(O(n\log n)\)。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,q,id[500100],S,cnt=1;
struct Suffix_Automaton{int ch[26],len,fa;}t[1100100];
int Add(int x,int c){
if(t[x].ch[c]){
int y=t[x].ch[c];
if(t[y].len==t[x].len+1)return y;//(x,c) has been added into the tree already.
int yy=++cnt;t[yy]=t[y];
t[yy].len=t[x].len+1,t[y].fa=yy;
for(;x&&t[x].ch[c]==y;x=t[x].fa)t[x].ch[c]=yy;
return yy;
}
int xx=++cnt;t[xx].len=t[x].len+1;
for(;x&&!t[x].ch[c];x=t[x].fa)t[x].ch[c]=xx;
if(!x){t[xx].fa=1;return xx;}
int y=t[x].ch[c];
if(t[y].len==t[x].len+1){t[xx].fa=y;return xx;}
int yy=++cnt;t[yy]=t[y];
t[yy].len=t[x].len+1;
t[y].fa=t[xx].fa=yy;
for(;x&&t[x].ch[c]==y;x=t[x].fa)t[x].ch[c]=yy;
return xx;
}
char s[500100];
int anc[1100100][20];
#define mid ((l+r)>>1)
int rt[1100100],tot;
struct dat{
int mx,pos;
dat(int X=0,int Y=0){mx=X,pos=Y;}
friend dat operator+(const dat&x,const dat&y){
if(x.mx>y.mx)return x;
if(x.mx<y.mx)return y;
return x.pos<y.pos?x:y;
}
};
struct SegTree{
int lson,rson;
dat val;
}seg[20010000];
void modify(int &x,int l,int r,int P){
if(l>P||r<P)return;
if(!x)x=++tot;
if(l==r){seg[x].val.mx++,seg[x].val.pos=P;return;}
modify(seg[x].lson,l,mid,P),modify(seg[x].rson,mid+1,r,P),seg[x].val=seg[seg[x].lson].val+seg[seg[x].rson].val;
}
dat query(int x,int l,int r,int L,int R){
if(l>R||r<L||!x)return dat();
if(L<=l&&r<=R)return seg[x].val;
return query(seg[x].lson,l,mid,L,R)+query(seg[x].rson,mid+1,r,L,R);
}
int merge(int x,int y,int l,int r){
if(!x||!y)return x+y;
int z=++tot;
if(l==r)seg[z].val=dat(seg[x].val.mx+seg[y].val.mx,l);
else seg[z].val=seg[seg[z].lson=merge(seg[x].lson,seg[y].lson,l,mid)].val+seg[seg[z].rson=merge(seg[x].rson,seg[y].rson,mid+1,r)].val;
return z;
}
vector<int>v[1100100];
void dfs(int x){for(auto y:v[x])dfs(y),rt[x]=merge(rt[x],rt[y],1,m);}
int substring(int l,int r){
int x=id[r-1];
for(int i=19;i>=0;i--)if(anc[x][i]&&t[anc[x][i]].len>=r-l+1)x=anc[x][i];
return x;
}
int main(){
scanf("%s",s),n=strlen(s);
for(int i=0,las=1;i<n;i++)las=id[i]=Add(las,s[i]-'a');
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%s",s),S=strlen(s);
for(int j=0,las=1;j<S;j++)modify(rt[las=Add(las,s[j]-'a')],1,m,i);
}
for(int i=2;i<=cnt;i++)v[anc[i][0]=t[i].fa].push_back(i);
dfs(1);
for(int j=1;j<=19;j++)for(int i=1;i<=cnt;i++)anc[i][j]=anc[anc[i][j-1]][j-1];
scanf("%d",&q);
for(int i=1,l,r,L,R;i<=q;i++){
scanf("%d%d%d%d",&L,&R,&l,&r);
int x=substring(l,r);
dat tmp=query(rt[x],1,m,L,R);
if(tmp.mx==0)printf("%d %d\n",L,0);
else printf("%d %d\n",tmp.pos,tmp.mx);
}
return 0;
}