rt,标题吸引大佬回答
具体思路:广义SAM,然后动态开点线段树处理每个SAM上的结点,线段树范围为 1-m ,然后在parent树上进行线段树合并。对于每个询问倍增在parent树上找到从 1 开始的等效区间,线段树查询
调了一下午+一晚上,没找出问题,cf第二个点 某个询问应该输出 4 1 ,程序输出了 3 1,数据点太大,弄不下来
求 hack 数据,或指出具体错误
谢绝无意义评论
代码
#include<stdio.h>
#include<iostream>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn=500005;
const int maxm=50005;
int q,m,rt[maxn<<1];
char s[maxn],temp[maxm];
inline int read(void)
{
int num,sign=1;char c;
while(!isdigit(c=getchar()))if(c=='-')sign=0;num=c-'0';
while(isdigit(c=getchar()))num=(num<<1)+(num<<3)+c-'0';
return sign?num:-num;
}
struct nodeans
{
int ans,id;
friend bool operator>(nodeans x,nodeans y){return x.ans==y.ans?x.id<y.id:x.ans>y.ans;}
};
inline nodeans max(nodeans x,nodeans y){return x>y?x:y;}
struct segment_tree
{
int tot;
struct node
{
int ls,rs;
nodeans si;
}tr[(maxn+maxm)*26];
void modify(int &u,int l,int r,int pos)
{
if(!u)u=++tot;
if(l==r){++tr[u].si.ans,tr[u].si.id=l;return;}
int mid=(l+r)>>1;
if(mid>=pos)modify(tr[u].ls,l,mid,pos);
else modify(tr[u].rs,mid+1,r,pos);
tr[u].si=max(tr[tr[u].ls].si,tr[tr[u].rs].si);
}
void merge(int &x,int y,int l,int r)
{
if(!x||!y)return x=x|y,void();
if(l==r){tr[x].si.ans+=tr[y].si.ans;return;}
int mid=(l+r)>>1;
merge(tr[x].ls,tr[y].ls,l,mid);
merge(tr[x].rs,tr[y].rs,mid+1,r);
tr[x].si=max(tr[tr[x].ls].si,tr[tr[x].rs].si);
}
nodeans query(int u,int l,int r,int x,int y)
{
if(l>=x&&r<=y)return tr[u].si;
int mid=(l+r)>>1;
if(mid>=y)return query(tr[u].ls,l,mid,x,y);
else if(mid<x)return query(tr[u].rs,mid+1,r,x,y);
return max(query(tr[u].ls,l,mid,x,y),query(tr[u].rs,mid+1,r,x,y));
}
}supccz;
struct suffix_automaton
{
int la=1,tot=1,ins[(maxn+maxm)<<1],cnt;
int head[(maxn+maxm)<<1],cnt_edge,pos[maxn];
int st[22][(maxn+maxm)<<1];
struct node
{
int fa,len,ch[26];
}tr[(maxn+maxm)<<1];
struct edge
{
int v,last;
}e[(maxn+maxm)<<1];
inline void addedge(int u,int v){e[++cnt_edge].last=head[u],e[cnt_edge].v=v,head[u]=cnt_edge;}
inline void insert(int x,int id)
{
if(tr[la].ch[x])
{
int p=la,u=tr[la].ch[x];
if(tr[p].len+1==tr[u].len)
{
la=u;
if(id)supccz.modify(rt[u],1,m,id);
else pos[++cnt]=la;
return;
}
int nu=++tot;
tr[nu]=tr[u],tr[nu].len=tr[p].len+1;
while(p&&tr[p].ch[x]==u)tr[p].ch[x]=nu,p=tr[p].fa;
tr[u].fa=nu,la=nu;
if(id)supccz.modify(rt[nu],1,m,id);
else pos[++cnt]=la;
return;
}
int p=la,u=++tot;
tr[u].len=tr[p].len+1;
while(p&&!tr[p].ch[x])tr[p].ch[x]=u,p=tr[p].fa;
if(!p)tr[u].fa=p+1;
else
{
int q=tr[p].ch[x];
if(tr[q].len==tr[p].len+1)tr[u].fa=q;
else
{
int nu=++tot;
tr[nu]=tr[q],tr[nu].len=tr[p].len+1;
while(p&&tr[p].ch[x]==q)tr[p].ch[x]=nu,p=tr[p].fa;
tr[q].fa=tr[u].fa=nu;
}
}
la=u;
if(id)supccz.modify(rt[u],1,m,id);
else pos[++cnt]=la;
}
void dfs(int u)
{
for(register int i=head[u];i;i=e[i].last)
{
int v=e[i].v;st[0][v]=u;
dfs(v);
supccz.merge(rt[u],rt[v],1,m);
}
}
inline void linktree(void)
{
for(register int i=2;i<=tot;++i)addedge(tr[i].fa,i);dfs(1);
for(register int j=1;j<=21;++j)
for(register int i=1;i<=tot;++i)st[j][i]=st[j-1][st[j-1][i]];
}
inline int getsq(int x,int len)
{
x=pos[x];
for(register int i=21;~i;--i)if(st[i][x]&&tr[st[i][x]].len>=len)x=st[i][x];
return x;
}
inline void solve(int l,int r,int x,int y)
{
nodeans ans=supccz.query(rt[getsq(y,y-x+1)],1,m,l,r);
if(!ans.ans)ans.id=l;
printf("%d %d\n",ans.id,ans.ans);
}
}ccz;
signed main(void)
{
scanf("%s",s);
m=read();
for(register int i=1;i<=m;++i)
{
ccz.la=1;
scanf("%s",temp);
int len=strlen(temp);
for(register int j=0;j<len;++j)ccz.insert(temp[j]-'a',i);
}
ccz.la=1;
int len=strlen(s);
for(register int i=0;i<len;++i)ccz.insert(s[i]-'a',0);
ccz.linktree();
q=read();
for(register int l,r,ql,qr,i=1;i<=q;++i)
{
l=read(),r=read(),ql=read(),qr=read();
ccz.solve(l,r,ql,qr);
}
return 0;
}