bzoj2746 [HEOI2012]旅行问题 ( AC自动机 & fail树 +lca + hash )

来源:互联网 发布:数据结构课程设计java 编辑:程序博客网 时间:2024/05/18 00:03

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 longusing 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;}
原创粉丝点击