BZOJ-2746: [HEOI2012]旅行问题

[文章目录]

Description

yz是Z国的领导人,他规定每个地区的名字只能为26个小写拉丁字母的一个。由于地 区数有可能超过26个,便产生了一个问题,如何辨别名字相同的地区?于是yz规定,一个 地区的描述必须包含它的所有上级,且上级按次序排列。于是,一个地区的描述是一个字符 串。比如说,一个地区的名字为c,它的上级为b,b的上级为a,a没有上级,那么这个地 区就描述为abc。显然,这个描述同时包含了c的上级b和b的上级a的描述,分别为ab和a。 值得注意的是,每个地区最多有一个上级,同一上级的地区之间名字不同,没有上级的 地区之间名字不同。现在,yz对外公布了n个地区的描述,这些描述中包含了Z国所有地区的描述,并让 你处理来访者的旅行问题。现有m对人访问这个国家,对于每对人,第一个人喜欢第i个描述中的第j个地区,设 这个地区描述为s1,第二个人喜欢第k个描述中的第l个地区,设这个地区描述为s2。他们为了统一行程,决定访问描述为s的地区(显然他们只关心地区的名字,并非是地区本身), 设s的长度为t,s需要满足以下条件:
1:t<=j, t<=l;
1:s[1..t] = s1[j-t+1 … j], s[1..t] = s2[l-t+1 … l];(即s为s1中1到k位 与s2中1到l位的公共后缀)
2:t最大化。
为了不使输出过大,你只需把这个字符串按照如下生成的26进制数转成10进制后mod 1000000007后输出。

就是求一个最长公共后缀,并且还是一个前缀。考虑一下,后缀相同???fail指针的交点???还要最长是个前缀???这不lca吗???所以就是求fail树上的lca。然后在build的时候就将串的10进制递推出来。就好了。

空间很值得注意啊。MLE*2.队列的空间炸了。另外lca初始化的时候没必要用bfs序。数组的就好多了直接循环下标。

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
int n,x1,x2,y1,y2,m;
char st[1001000];
const ll mod=1000000007;
struct trie
{
    trie *ch[26],*fa[22];
    int deep;
    int ans;
    trie()
    {
        memset(ch,0,sizeof(ch));
        memset(fa,0,sizeof(fa));
        deep=0; ans=0;
    }
}*root=new trie();

vector<trie*>map[1001000];

void insert(int x)
{
    int len=strlen(st+1);
    trie *p=root;
    for(int i=1;i<=len;i++)
    {
        if(!p->ch[st[i]-'a'])
            p->ch[st[i]-'a']=new trie(),p->ch[st[i]-'a']->ans=(1ll*p->ans*26%mod+st[i]-'a')%mod;
        p=p->ch[st[i]-'a'];
        map[x].push_back(p);
    }
}

void build_ac_auto()
{
    static trie* q[1000010];
    int l=1,r=0;
    for(int i=0;i<26;i++)
        if(root->ch[i])
            root->ch[i]->fa[0]=root,
            root->ch[i]->deep=1,
            q[++r]=root->ch[i];
    while(l<=r)
    {
        trie *p=q[l]; l++;
        for(int i=0;i<26;i++)
            if(p->ch[i])
            {
                trie* tmp=p->fa[0];
                while(tmp!=root&&!tmp->ch[i]) tmp=tmp->fa[0];
                if(tmp->ch[i]) tmp=tmp->ch[i];
                p->ch[i]->fa[0]=tmp;
                p->ch[i]->deep=tmp->deep+1;
                q[++r]=p->ch[i];
            }
    }
    for(int i=1;i<=20;i++)
        for(int j=1;j<=r;j++)
            q[j]->fa[i]=q[j]->fa[i-1]->fa[i-1];
}

trie* lca(trie* x,trie* y)
{
    if(x->deep<y->deep) swap(x,y);
    for(int i=20;i>=0;i--)
        if(x->fa[i]->deep>=y->deep) x=x->fa[i];
    if(x==y) return x;
    for(int i=20;i>=0;i--)
        if(x->fa[i]!=y->fa[i]) x=x->fa[i],y=y->fa[i];
    return x->fa[0];
}
int main()
{
    for(int i=0;i<=20;i++) root->fa[i]=root;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",st+1);
        insert(i);
    }
    build_ac_auto();
    scanf("%d",&m);
    while(m--)
    {
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        printf("%d\n",lca(map[x1][y1-1],map[x2][y2-1])->ans);
    }
    return 0;
}

 

发表评论

邮箱地址不会被公开。 必填项已用*标注