bzoj 2746: [HEOI2012]旅行问题 AC自动机fail树

2746: [HEOI2012]旅行问题

Time Limit: 30 Sec  Memory Limit: 256 MB
Submit: 489  Solved: 174
[Submit][Status][Discuss]

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后输出: 
a->0 
b->1 



z->25 
比如地区cab被编码成2 *    26? + 0 * 26? + 1 * 26? = 1353。 

Input

第一行给定一个整数n 
第2…n+1行:每i+1行给定一个字符串a[i],表示第i个描述。 
接下来一行一个整数m 
接下来m行:每行给定四个整数i,j,k,l,字母含义与题目描述一致。 

Output


共m行,每行一个整数,表示答案字符串的编码。 

Sample Input

2
aabb babb
2
1 3 2 3
1 4 2 4

Sample Output

1
1
【样例说明】
询问1中的公共后缀有ab和b,但是没有ab这个地区,只有b地区,所以只能选择b这个 地区;
询问2中的公共后缀有abb、bb和b,但是没有abb和bb这两个地区,只有b地区,所以 只能选择b这个地区。

HINT

【数据范围】


 设这个国家地区总数数为tot(注意:输入的字符串总长度可能超过tot!) 对于30%的数据,满足tot,m,n<=100; 

对于50%的数据,满足tot,m,n<=1000; 

对于80%的数据,满足tot,m,n<=100000; 

对于100%的数据,满足tot,m,n<=1000000; 

保证输入文件不超过20MB。 

  fail树建出来,查询两点间lca

  这道题没什么好说的,丧心病狂的卡空间,卡常数,由于链表数组少开了一倍,导致RE,还以为是字符数组必须开到2*1e6的大小,然后连trie树指针都优化成了链表,虽然这优化确实没有什么用,但是把空间给降下来了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
#define MAXN 1000010
#define MAXV MAXN
#define MAXE MAXV
#define MAXLEN 20*1024*1024
#define MOD 1000000007
typedef long long qword;
inline int nextInt()
{
        register int x=0;
        register char ch;
        while (ch=(char)getchar(),ch<'0' || ch>'9');
        while (x=x*10+ch-'0',ch=(char)getchar(),ch<='9' && ch>='0');
        return x;
}
struct Edge
{
        int np;
        Edge *next;
}E[MAXE],*V[MAXV];
int tope=-1;
void addedge(int x,int y)
{
        E[++tope].np=y;
        E[tope].next=V[x];
        V[x]=&E[tope];
}
struct TEdge
{
        int idx,ptr;
        TEdge *next;
}TE[MAXN];
int topte=-1;
struct trie_node
{
        TEdge *nxt;
        int fail;
        int hash;
}trie[MAXN];
int root=0;
int topt=0;
void Add_trie(char *str,int *ptr)
{
        TEdge *ne;
        int now=root;
        int hash=0;
        bool flag;
        while (*str)
        {
                hash=(int)(((qword)hash*26+*str-'a')%MOD);
                int idx=*(str++)-'a';
                flag=false;
                for (ne=trie[now].nxt;ne;ne=ne->next)
                {
                        if (ne->idx==idx)
                        {
                                flag=true;
                                now=ne->ptr;
                        }
                }
                if (!flag)
                {
                        TE[++topte].idx=idx;
                        TE[topte].ptr=++topt;
                        TE[topte].next=trie[now].nxt;
                        trie[now].nxt=&TE[topte];
                        now=TE[topte].ptr;
                }
                trie[now].hash=hash;
                *(ptr++)=now;
        }
}
int q[MAXN];
void Build_AC()
{
        int head=-1,tail=0;
        int now;
        trie[root].fail=root;
        q[0]=root;
        now=q[++head];
        TEdge *tne,*tn2;
        for (tne=trie[root].nxt;tne;tne=tne->next)
        {
                trie[tne->ptr].fail=root;
                q[++tail]=tne->ptr;
        }
        while (head<tail)
        {
                now=q[++head];
                for (tne=trie[now].nxt;tne;tne=tne->next)
                {
                        for (int j=trie[now].fail;j!=root;j=trie[j].fail)
                        {
                                for (tn2=trie[j].nxt;tn2;tn2=tn2->next)
                                {
                                        if (tn2->idx==tne->idx)
                                        {
                                                trie[tne->ptr].fail=tn2->ptr;
                                                break;
                                        }
                                }
                                if (trie[tne->ptr].fail)break;
                        }
                        if (!trie[tne->ptr].fail)
                                for (tn2=trie[root].nxt;tn2;tn2=tn2->next)
                                        if (tn2->idx==tne->idx)
                                                trie[tne->ptr].fail=tn2->ptr;
                        q[++tail]=tne->ptr;
                }
        }
        for (int i=1;i<=tail;i++)
        {
                now=q[i];
                addedge(trie[now].fail,now);
        }
}

char str[MAXLEN];
int ptr[MAXLEN];
int shead[MAXN];
struct Link
{
        int val,id;
        Link *next;
}LE[MAXN*2],*LK[MAXN];
int topl=-1;
inline void addlink(int x,int y,int id)
{
        LE[++topl].val=y;
        LE[topl].id=id;
        LE[topl].next=LK[x];
        LK[x]=&LE[topl];
}
int stack[MAXN];
bool vis[MAXN];
int uf[MAXN];
int res[MAXN];
int get_fa(int now)
{
        return uf[now]==now ? now : uf[now]=get_fa(uf[now]);
}
void dfs(int now)
{
        int tops=-1;
        Edge *ne;
        Link *nl;
        stack[++tops]=now;
        while (~tops)
        {
                if (stack[tops]<0)
                {
                        now=-stack[tops--];
                        uf[get_fa(now)]=get_fa(trie[now].fail);
                }else
                {
                        now=stack[tops];
                        vis[now]=true;
                        for (nl=LK[now];nl;nl=nl->next)
                        {
                                if (vis[nl->val])
                                {
                                        res[nl->id]=trie[get_fa(nl->val)].hash;
                                }
                        }
                        if (!stack[tops])
                                tops--;
                        else
                                stack[tops]=-stack[tops];
                        for (ne=V[now];ne;ne=ne->next)
                        {
                                stack[++tops]=ne->np;
                        }
                }
        }
}

int main()
{
        freopen("input.txt","r",stdin);
        int n;
        scanf("%d
",&n);
        for (int i=0;i<n;i++)
        {
                scanf("%s",str+shead[i]);
                Add_trie(str+shead[i],ptr+shead[i]);
                shead[i+1]=shead[i]+strlen(str+shead[i]);
        }
        Build_AC();
        int m;
        int x,y;
        scanf("%d",&m);
        int a,b,c,d;
        for (int i=0;i<m;i++)
        {
                a=nextInt();b=nextInt();c=nextInt();d=nextInt();
                a--,b--,c--,d--;
                x=ptr[shead[a]+b];
                y=ptr[shead[c]+d];
                addlink(x,y,i);
                addlink(y,x,i);
        }
        for (int i=0;i<=topt;i++)
                uf[i]=i;
        dfs(0);
        for (int i=0;i<m;i++)
                printf("%d
",res[i]);
}
原文地址:https://www.cnblogs.com/mhy12345/p/4376731.html