bzoj2746 [HEOI2012]旅行问题
原题地址:http://www.lydsy.com/JudgeOnline/problem.php?id=2746
题意:
给定n个字符串,共有m次询问,每次询问输入四个数S1,L1,S2,L2,表示求第S1个字符串长度为L1的前缀,和第S2个字符串长度为L2的前缀,的最长公共后缀,满足这个后缀是给定的某一个串的前缀。
为了不使输出过大,你只需把这个字符串按照如下生成的26进制数转成10进制后mod 1000000007后输出:
a->0
b->1
…
z->25
比如cab被编码成2 * 26^2 + 0 * 26^1 + 1 * 26^0 = 1353。
数据范围
m,n<=1000000;
保证输入文件不超过20MB。
题解:
fail树的应用。
两个串的最长公共后缀就是他们在fail树上的lca。
输入时把每个字符串插入Trie树时,顺便保存每个位置26进制后的值,以及每个位置对应Trie树上点的编号。
求fail时就干脆向倍增求lca一样,fail[u][p]就是u点向上跳2^p步得到的点。
最后直接输出lca的26进制hash值。
刚好100行☆
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#define LL long long
using namespace std;
const int N=1<<20;
const int mod=1000000007;
const int P=21;
queue<int> Q;
int n,m,ch[N][26],fail[N][25],dep[N],tail=0,cnt=0,pos[N<<1],lenth[N];
char str[N];
LL Hash[N];
void insert()
{
int len=strlen(str);
int p=0; LL mark=0;
for(int i=0;i<len;i++)
{
int c=str[i]-'a';
if(!ch[p][c])
{
ch[p][c]=++tail;
Hash[ch[p][c]]=(((Hash[p]*26)%mod)+c)%mod;
}
pos[++cnt]=ch[p][c];
p=ch[p][c];
}
}
void getfail()
{
dep[0]=0;
for(int i=0;i<26;i++)
if(ch[0][i])
{
fail[ch[0][i]][0]=0;
dep[ch[0][i]]=1;
Q.push(ch[0][i]);
}
while(!Q.empty())
{
int top=Q.front(); Q.pop();
for(int i=0;i<26;i++)
{
if(!ch[top][i])
{
ch[top][i]=ch[fail[top][0]][i];
continue;
}
int u=ch[top][i];
fail[u][0]=ch[fail[top][0]][i];
dep[u]=dep[fail[u][0]]+1;
for(int j=1;j<P;j++)
fail[u][j]=fail[fail[u][j-1]][j-1];
Q.push(u);
}
}
}
int getlca(int u,int v)
{
if(dep[u]<dep[v]) swap(u,v);
int d=dep[u]-dep[v];
for(int i=0;d;d>>=1,i++)
if(d&1) u=fail[u][i];
if(u==v) return u;
for(int p=P-1;p>=0;p--)
{
if(fail[u][p]!=fail[v][p])
{
u=fail[u][p];
v=fail[v][p];
}
}
return fail[u][0];
}
int main()
{
scanf("%d",&n);
memset(fail,0,sizeof(fail));
lenth[0]=0;
for(int i=1;i<=n;i++)
{
scanf("%s",str);
insert();
lenth[i]=strlen(str);
lenth[i]+=lenth[i-1];
}
getfail();
scanf("%d",&m);
while(m--)
{
int p1,l1,p2,l2;
scanf("%d%d%d%d",&p1,&l1,&p2,&l2);
int t1=pos[lenth[p1-1]+l1]; int t2=pos[lenth[p2-1]+l2];
int lca=getlca(t1,t2);
printf("%lld\n",Hash[lca]);
}
return 0;
}