bzoj 2746 旅行问题 Posted on 2019-10-30 | Views: $AC$ 自动机. 插入串的时候同时记录一下每个前缀在自动机上的编号以及 $Hash$ 值. 询问时,要求的公共后缀就是那两个前缀在 $fail$ 树上的 $LCA$ . 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100//%std#include<bits/stdc++.h>using namespace std;typedef long long ll;inline int read(){ int out=0,fh=1; char jp=getchar(); while ((jp>'9'||jp<'0')&&jp!='-') jp=getchar(); if (jp=='-') fh=-1,jp=getchar(); while (jp>='0'&&jp<='9') out=out*10+jp-'0',jp=getchar(); return out*fh;}const int P=1e9+7;int add(int a,int b){ return (a+b>=P)?(a+b-P):(a+b);}int mul(int a,int b){ return 1LL * a * b % P;}const int MAXN=1e6+10,S=26,K=22;int n,ch[MAXN][S],fail[MAXN],Hash[MAXN],idx=0;int fa[MAXN][K],dep[MAXN];vector<int> pos[MAXN];char buf[MAXN];queue<int> q;void getfail(){ for(int i=0;i<S;++i) if(ch[0][i]) { q.push(ch[0][i]); dep[ch[0][i]]=1; } while(!q.empty()) { int u=q.front(); q.pop(); for(int i=0;i<S;++i) if(ch[u][i]) { q.push(ch[u][i]); int x=ch[u][i],y=ch[fail[u]][i]; fail[x]=fa[x][0]=y; dep[x]=dep[y]+1; for(int j=1;(1<<j)<=dep[x];++j) fa[x][j]=fa[fa[x][j-1]][j-1]; } else ch[u][i]=ch[fail[u]][i]; }}int LCA(int x,int y){ if(dep[x]<dep[y]) swap(x,y); for(int i=K-1;i>=0;--i) if((1<<i)<=dep[x]-dep[y]) x=fa[x][i]; if(x==y) return x; for(int i=K-1;i>=0;--i) if((1<<i)<=dep[x] && fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; }int main(){ n=read(); for(int i=1;i<=n;++i) { int x=scanf("%s",buf); pos[i].push_back(0); int u=0,m=strlen(buf); for(int j=0;j<m;++j) { int c=buf[j]-'a'; if(!ch[u][c]) ch[u][c]=++idx; Hash[ch[u][c]]=add(mul(Hash[u],S),c); u=ch[u][c]; pos[i].push_back(u); } } getfail(); int m=read(); for(int i=1;i<=m;++i) { int x=read(),px=read(),y=read(),py=read(); px=pos[x][px],py=pos[y][py]; int pz=LCA(px,py); printf("%d\n",Hash[pz]); } return 0;}