CF66E Forensic Examination 题解
继续考虑建立后缀自动机,那么我们查询答案相当于找到最小的包含\(s[l,r]\)的节点,然后求出这个节点子树中\([T_l,T_r]\)出现的次数的最大值以及对应的下标,我们可以找到每一个\(s[1,r]\)的位置,然后倍增,如果说你像我一样弱,不会在广义\(SAM\)中找匹配,你可以把\(s\)也丢进广义\(SAM\),这样一定有匹配,可以直接往儿子节点跳,容易发现此时一定有对应的儿子节点给你跳,代码容易实现,但是时空均比较劣。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=6e5+10;
string s,tt;
int lst,tot=1,n,m,x,y,xx,yy,pre[maxn],idd,now;
struct edge{
int ch[26];
int fa[21];
int link;
int len;
int rt;
}tree[maxn<<1];
struct node{
int ying;
int mx;
int ls;
int rs;
}t[maxn<<5];
vector<int>tu[maxn<<1];
void insert(int c){
if(tree[lst].ch[c]&&tree[lst].len+1==tree[tree[lst].ch[c]].len){
lst=tree[lst].ch[c];
return;
}
int p=lst,np,q,nq;
tot++;
np=tot;
tree[np].len=tree[p].len+1;
for(;p&&!tree[p].ch[c];p=tree[p].link){
tree[p].ch[c]=np;
}
if(!p){
tree[np].link=1;
}
else{
q=tree[p].ch[c];
if(tree[p].len+1==tree[q].len){
tree[np].link=q;
}
else{
tot++;
nq=tot;
tree[nq]=tree[q];
tree[nq].rt=0;
tree[nq].len=tree[p].len+1;
tree[q].link=nq;
tree[np].link=nq;
for(;p&&tree[p].ch[c]==q;p=tree[p].link){
tree[p].ch[c]=nq;
}
}
}
lst=np;
return;
}
void push_up(int id){
if(t[t[id].ls].mx>=t[t[id].rs].mx){
t[id].mx=t[t[id].ls].mx;
t[id].ying=t[t[id].ls].ying;
}
else{
t[id].mx=t[t[id].rs].mx;
t[id].ying=t[t[id].rs].ying;
}
return;
}
void add(int &id,int l,int r,int q){
if(!id){
idd++;
id=idd;
}
if(l==r){
t[id].mx++;
t[id].ying=l;
return;
}
int mid=(l+r)/2;
if(q<=mid){
add(t[id].ls,l,mid,q);
}
else{
add(t[id].rs,mid+1,r,q);
}
push_up(id);
return;
}
int merge(int q,int w){
if(!q||!w){
return q+w;
}
idd++;
int zhi=idd;
if(!t[q].ls&&!t[q].rs){
t[zhi].mx=t[q].mx+t[w].mx;
t[zhi].ying=t[q].ying;
return zhi;
}
t[zhi].ls=merge(t[q].ls,t[w].ls);
t[zhi].rs=merge(t[q].rs,t[w].rs);
push_up(zhi);
return zhi;
}
int query_mx(int id,int l,int r,int q,int w){
if(q<=l&&r<=w){
return t[id].mx;
}
int mid=(l+r)/2;
if(w<=mid){
return query_mx(t[id].ls,l,mid,q,w);
}
else if(q>mid){
return query_mx(t[id].rs,mid+1,r,q,w);
}
else{
return max(query_mx(t[id].ls,l,mid,q,w),query_mx(t[id].rs,mid+1,r,q,w));
}
}
int query_shu(int id,int l,int r,int q,int w,int qw){
if(t[id].mx<qw){
return 0;
}
if(l==r){
return l;
}
int now=0,mid=(l+r)/2;
if(q<=mid){
now=query_shu(t[id].ls,l,mid,q,w,qw);
}
if(w>mid&&!now){
now=query_shu(t[id].rs,mid+1,r,q,w,qw);
}
return now;
}
void query(int id,int l,int r){
int now=query_mx(tree[id].rt,1,n,l,r);
cout<<query_shu(tree[id].rt,1,n,l,r,now)<<' '<<now<<'\n';
return;
}
void dfss(int q){
for(int i=1;i<=20;i++){
tree[q].fa[i]=tree[tree[q].fa[i-1]].fa[i-1];
}
for(int i=(int)tu[q].size()-1;i>=0;i--){
dfss(tu[q][i]);
tree[q].rt=merge(tree[q].rt,tree[tu[q][i]].rt);
}
return;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>s;
lst=1;
for(int i=0;i<(int)s.size();i++){
insert(s[i]-'a');
}
cin>>n;
for(int i=1;i<=n;i++){
cin>>tt;
lst=1;
for(int j=0;j<(int)tt.size();j++){
insert(tt[j]-'a');
add(tree[lst].rt,1,n,i);
}
}
for(int i=2;i<=tot;i++){
tu[tree[i].link].push_back(i);
tree[i].fa[0]=tree[i].link;
}
dfss(1);
pre[0]=1;
for(int i=1;i<=(int)s.size();i++){
pre[i]=tree[pre[i-1]].ch[s[i-1]-'a'];
}
cin>>m;
for(int i=1;i<=m;i++){
cin>>x>>y>>xx>>yy;
now=pre[yy];
for(int j=20;j>=0;j--){
if(tree[tree[now].fa[j]].len>=yy-xx+1){
now=tree[now].fa[j];
}
}
query(now,x,y);
}
return 0;
}
浙公网安备 33010602011771号