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=;
register char ch;
while (ch=(char)getchar(),ch<'' || ch>'');
while (x=x*+ch-'',ch=(char)getchar(),ch<='' && ch>='');
return x;
}
struct Edge
{
int np;
Edge *next;
}E[MAXE],*V[MAXV];
int tope=-;
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=-;
struct trie_node
{
TEdge *nxt;
int fail;
int hash;
}trie[MAXN];
int root=;
int topt=;
void Add_trie(char *str,int *ptr)
{
TEdge *ne;
int now=root;
int hash=;
bool flag;
while (*str)
{
hash=(int)(((qword)hash*+*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=-,tail=;
int now;
trie[root].fail=root;
q[]=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=;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*],*LK[MAXN];
int topl=-;
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=-;
Edge *ne;
Link *nl;
stack[++tops]=now;
while (~tops)
{
if (stack[tops]<)
{
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",&n);
for (int i=;i<n;i++)
{
scanf("%s",str+shead[i]);
Add_trie(str+shead[i],ptr+shead[i]);
shead[i+]=shead[i]+strlen(str+shead[i]);
}
Build_AC();
int m;
int x,y;
scanf("%d",&m);
int a,b,c,d;
for (int i=;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=;i<=topt;i++)
uf[i]=i;
dfs();
for (int i=;i<m;i++)
printf("%d\n",res[i]);
}

bzoj 2746: [HEOI2012]旅行问题 AC自动机fail树的更多相关文章

  1. (RERERERERERERERERERERE) BZOJ 2746: [HEOI2012]旅行问题

    二次联通门 : BZOJ 2746: [HEOI2012]旅行问题 神TM STL的vector push_back进一个数后取出时就变成了一个很小的负数.. 调不出来了, 不调了 #include ...

  2. BZOJ 2746: [HEOI2012]旅行问题

    2746: [HEOI2012]旅行问题 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 921  Solved: 291[Submit][Status ...

  3. BZOJ2746: [HEOI2012]旅行问题(AC自动机 LCA)

    Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 1188  Solved: 383[Submit][Status][Discuss] Descripti ...

  4. BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2545  Solved: 1419[Submit][Sta ...

  5. BZOJ 3172: [Tjoi2013]单词 [AC自动机 Fail树]

    3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 3198  Solved: 1532[Submit][Status ...

  6. BZOJ 2905: 背单词 AC自动机+fail树+dfs序+线段树

    Description 给定一张包含N个单词的表,每个单词有个价值W.要求从中选出一个子序列使得其中的每个单词是后一个单词的子串,最大化子序列中W的和. Input 第一行一个整数TEST,表示数据组 ...

  7. BZOJ 2434: [Noi2011]阿狸的打字机 AC自动机+fail树+线段树

    Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...

  8. 【BZOJ-2434】阿狸的打字机 AC自动机 + Fail树 + DFS序 + 树状数组

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2022  Solved: 1158[Submit][Sta ...

  9. 【BZOJ-3881】Divljak AC自动机fail树 + 树链剖分+ 树状数组 + DFS序

    3881: [Coci2015]Divljak Time Limit: 20 Sec  Memory Limit: 768 MBSubmit: 508  Solved: 158[Submit][Sta ...

随机推荐

  1. HTML增加删除邮件(table)

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  2. ASP.net导出EXCEL乱码?试试这个

    网上的方法有说加meta的,是有用,不过,不够直接, 甭管你asp文件是utf-8还是gb2312,加入下面两句就搞掂: response.Charset="GB2312" ses ...

  3. Android_EditText

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools=&q ...

  4. C#扫盲之:静态成员、静态方法、静态类、实例成员及区别

    文章目录 1.静态成员.实例成员 2.静态类 3.类的静态成员和非静态成员区别 --------------------------------------分割线------------------- ...

  5. 自己动手用Javascript写一个无刷新分页控件

    .NET技术交流群:337901356 ,欢迎您的加入! 对 于一个用户体验好的网站来说,无刷新技术是很重要的,无刷新,顾名思义,就是局部刷新数据,有用过Asp.net Web Form技术开发网页的 ...

  6. 使用ICSharpZipLib将文件夹压缩为zip文件

    序言:     在我接触Git和SVN之前,我最常用的保存数据的办法就是把文件夹压缩成一个zip文件,添加上时间戳.下面是我在学习C#的文件操作之后做的一个练习,使用开源的ICSharpZipLib来 ...

  7. 20160127 linux 学习笔记

    Linux学习笔记第一天 Linux基本介绍 Linux的起源和发展: 简单说linux是一种操作系统,可以安装在包括服务器.个人电脑,乃至PDA.手机.打印机等各类设备中. 起源: Linux起源于 ...

  8. 20151221jquery学习笔记---日历UI

    妹的,这几天真是无语了,参加了一个无聊的比赛,简直浪费时间,好几天没学jquery啊,今天学了一点,不过快要期末考试了,估计得攒到寒假了啊. 日历(datepicker) UI, 可以让用户更加直观的 ...

  9. Eclipse中绑定java源代码

    如何在Eclipse sdk中查看jar源代码如:*.jar  1.点 “window”-> "Preferences" -> "Java" -&g ...

  10. python中关于正则表达式四

    []   用来暗示一个字符串集合, 1.在这个集合中:字符串可以被 独特列出,例如[amk]将会匹配'a','m'或者'k'. 2.字符串的范围可以被暗示通过给两个字符串和分开它们用一个'-':例如[ ...