CF666E Forensic Examination
思路
线段树合并+广义SAM
先把所有串都插入SAM中,然后用线段树合并维护right集合,对S匹配的同时离线询问,然后就好啦
代码
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN = 100100;
const int MAXlog = 20;
char s[500500],t[50500];
int lens,m,q;
namespace Segment_Tree{
int Nodecnt=0,root[100100];
struct Node{
int lson,rson,maxx,maxnum;
}Seg[100100*50];
void pushup(int o){
if(Seg[Seg[o].lson].maxx>Seg[Seg[o].rson].maxx){
Seg[o].maxx=Seg[Seg[o].lson].maxx;
Seg[o].maxnum=Seg[Seg[o].lson].maxnum;
}
else if(Seg[Seg[o].rson].maxx>Seg[Seg[o].lson].maxx){
Seg[o].maxx=Seg[Seg[o].rson].maxx;
Seg[o].maxnum=Seg[Seg[o].rson].maxnum;
}
else if(Seg[Seg[o].rson].maxx==Seg[Seg[o].lson].maxx){
if(Seg[Seg[o].lson].maxnum<Seg[Seg[o].rson].maxnum){
Seg[o].maxx=Seg[Seg[o].lson].maxx;
Seg[o].maxnum=Seg[Seg[o].lson].maxnum;
}
else{
Seg[o].maxx=Seg[Seg[o].rson].maxx;
Seg[o].maxnum=Seg[Seg[o].rson].maxnum;
}
}
}
void merge(int l,int r,int &lroot,int rroot){// rroot -> lroot
if(lroot*rroot==0){
lroot=lroot+rroot;
return;
}
if(l==r){
Seg[lroot].maxx+=Seg[rroot].maxx;
Seg[lroot].maxnum=l;
return;
}
int mid=(l+r)>>1;
merge(l,mid,Seg[lroot].lson,Seg[rroot].lson);
merge(mid+1,r,Seg[lroot].rson,Seg[rroot].rson);
pushup(lroot);
}
void add(int l,int r,int pos,int &o){
if(!o)
o=++Nodecnt;
if(l==r){
Seg[o].maxx++;
Seg[o].maxnum=pos;
return;
}
int mid=(l+r)>>1;
if(pos<=mid)
add(l,mid,pos,Seg[o].lson);
else
add(mid+1,r,pos,Seg[o].rson);
pushup(o);
}
Node query(int L,int R,int l,int r,int o){
if(!o)
return (Node){0,0,0,L};
if(L<=l&&r<=R)
return Seg[o];
int mid=(l+r)>>1;
if(R<=mid)
return query(L,R,l,mid,Seg[o].lson);
else{
if(L>mid)
return query(L,R,mid+1,r,Seg[o].rson);
else{
Node ans,lx=query(L,R,l,mid,Seg[o].lson),rx=query(L,R,mid+1,r,Seg[o].rson);
if(lx.maxx>rx.maxx){
ans.maxx=lx.maxx;
ans.maxnum=lx.maxnum;
}
else if(rx.maxx>lx.maxx){
ans.maxx=rx.maxx;
ans.maxnum=rx.maxnum;
}
else{
if(lx.maxnum<rx.maxnum){
ans.maxx=lx.maxx;
ans.maxnum=lx.maxnum;
}
else{
ans.maxx=rx.maxx;
ans.maxnum=rx.maxnum;
}
}
return ans;
}
}
}
}
namespace SAM{
int Nodecnt=1,trans[MAXN][26],maxlen[MAXN],suflink[MAXN];
int New_state(int _maxlen,int *_trans,int _suflink){
++Nodecnt;
maxlen[Nodecnt]=_maxlen;
if(_trans)
for(int i=0;i<26;i++)
trans[Nodecnt][i]=_trans[i];
suflink[Nodecnt]=_suflink;
return Nodecnt;
}
int add_len(int u,int c){
if(trans[u][c]){
int v=trans[u][c];
if(maxlen[v]==maxlen[u]+1)
return v;
int y=New_state(maxlen[u]+1,trans[v],suflink[v]);
suflink[v]=y;
while(u&&trans[u][c]==v){
trans[u][c]=y;
u=suflink[u];
}
return y;
}
else{
int z=New_state(maxlen[u]+1,NULL,0);
while(u&&trans[u][c]==0){
trans[u][c]=z;
u=suflink[u];
}
if(!u){
suflink[z]=1;
return z;
}
int v=trans[u][c];
if(maxlen[v]==maxlen[u]+1){
suflink[z]=v;
return z;
}
int y=New_state(maxlen[u]+1,trans[v],suflink[v]);
suflink[v]=suflink[z]=y;
while(u&&trans[u][c]==v){
trans[u][c]=y;
u=suflink[u];
}
return z;
}
}
void insert(char *s,int len,int inq){
int last=1;
for(int i=1;i<=len;i++){
last=add_len(last,s[i]-'a');
Segment_Tree::add(1,m,inq,Segment_Tree::root[last]);
// printf("o=%d\n",last);
}
}
void debug(void){
for(int i=1;i<=Nodecnt;i++){
printf("%d: maxlen=%d suflink=%d\n",i,maxlen[i],suflink[i]);
}
}
}
namespace parent_tree{
int fir[100100],v[100100],nxt[100100],cnt,fa[100100][MAXlog];
void addedge(int ui,int vi){
++cnt;
v[cnt]=vi;
nxt[cnt]=fir[ui];
fir[ui]=cnt;
}
void build(void){
for(int i=2;i<=SAM::Nodecnt;i++){
addedge(SAM::suflink[i],i);
fa[i][0]=SAM::suflink[i];
}
}
void pre(void){
build();
for(int i=1;i<MAXlog;i++){
for(int j=1;j<=SAM::Nodecnt;j++)
fa[j][i]=fa[fa[j][i-1]][i-1];
}
}
void debug(void){
for(int i=0;i<16;i++){
for(int j=1;j<=SAM::Nodecnt;j++)
printf("fa[%d][%d]=%d\n",j,i,fa[j][i]);
}
}
}
struct Ask{
int l,r,pl,pr,which,times;
}Q[500500];
struct table{
int fir[500500],v[500500],nxt[500500],cnt;
void add(int u,int num){
++cnt;
v[cnt]=num;
nxt[cnt]=fir[u];
fir[u]=cnt;
}
}Qr,QN;
void dfs(int u){
for(int i=parent_tree::fir[u];i;i=parent_tree::nxt[i]){
dfs(parent_tree::v[i]);
Segment_Tree::merge(1,m,Segment_Tree::root[u],Segment_Tree::root[parent_tree::v[i]]);
}
for(int i=QN.fir[u];i;i=QN.nxt[i]){
int o=QN.v[i];
// printf("id=%d\n",o);
Segment_Tree::Node tmp=Segment_Tree::query(Q[o].l,Q[o].r,1,m,Segment_Tree::root[u]);
Q[o].which=tmp.maxnum;
Q[o].times=tmp.maxx;
// printf("which=%d time=%d\n",Q[o].which,Q[o].times);
}
}
int main(){
// freopen("test.in","r",stdin);
// freopen("test.out","w",stdout);
scanf("%s",s+1);
lens=strlen(s+1);
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%s",t+1);
SAM::insert(t,strlen(t+1),i);
}
// SAM::debug();
parent_tree::pre();
// parent_tree::debug();
scanf("%d",&q);
for(int i=1;i<=q;i++){
scanf("%d %d %d %d",&Q[i].l,&Q[i].r,&Q[i].pl,&Q[i].pr);
Qr.add(Q[i].pr,i);
}
int nowlen=0,nowp=1;
for(int i=0;i<lens;i++){
// printf("i=%d nowp=%d len=%d\n",i+1,nowp,nowlen);
if(SAM::trans[nowp][s[i+1]-'a']){
nowp=SAM::trans[nowp][s[i+1]-'a'];
nowlen++;
}
else{
while(nowp&&(SAM::trans[nowp][s[i+1]-'a']==0))
nowp=SAM::suflink[nowp];
if(!nowp){
nowp=1;
nowlen=0;
continue;
}
nowlen=SAM::maxlen[nowp]+1;
nowp=SAM::trans[nowp][s[i+1]-'a'];
}
for(int j=Qr.fir[i+1];j;j=Qr.nxt[j]){
// printf("id=%d\n",Qr.v[j]);
int lentmp=Q[Qr.v[j]].pr-Q[Qr.v[j]].pl+1;
if(nowlen<lentmp)
continue;
int tmpp=nowp;
for(int k=MAXlog-1;k>=0;k--)
if(SAM::maxlen[parent_tree::fa[tmpp][k]]>=lentmp)
tmpp=parent_tree::fa[tmpp][k];
QN.add(tmpp,Qr.v[j]);
// printf("getNode=%d\n",tmpp);
}
}
dfs(1);
for(int i=1;i<=q;i++){
if(Q[i].times)
printf("%d %d\n",Q[i].which,Q[i].times);
else
printf("%d %d\n",Q[i].l,Q[i].times);
}
return 0;
}