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. Android开发——避免内存泄露

    本文翻译自Avoiding memory leak——Post by Romain Guy 著作权归原作者所有.转载请注明出处,由JohnTsai翻译 Android应用被分配的堆的大小限制为16MB ...

  2. oracle Form Builer:FIND_FORM Built-in

    Description Searches the list of forms and returns a form module ID when it finds a valid form with ...

  3. case when then 与 count联合使用

    我们都知道SQL中适用case when then来转化数据库中的信息 比如  select (case sex when 0 then '男' else '女' end) AS sex  from ...

  4. JQuery设置input属性(disabled、enabled)

    document.getElementById("removeButton").disabled = false; //普通Js写法 $("#removeButton&q ...

  5. c语言学习之基础知识点介绍(十四):指针的进阶

    一.指针的加.减法运算 /* 1.加法运算 1).可以跟整数进行加法运算,得到的还是一个地址 公式: 地址 + 1 = 地址 + 1 * 类型所占的字节数 地址 + n = 地址 + n * 类型所占 ...

  6. Win7/Win8.1预订升级Win10失败临时解决方案

    很多Win7/Win8.1用户在今天凌晨通过微软官方推送的方式升级Win10,但这一过程中遇到了“安装失败”等问题,导致升级无法进行.鉴于这种情况,很多用户选择进入Windows10预下载安装文件夹打 ...

  7. selenium IDE处理各种窗口问题解决方法

    一.处理模态窗口:showModalDialog 由于弹出模态窗口后,就无法定位到当前窗口的元素和模态窗口的元素,需要添加js解决 模态窗口动作类似下面语句: <input id="c ...

  8. UiTextField对输入的长度进行限制并提示用户还可输入的长度

    最近想做用户昵称的限制,但是网上百度了很多方法效果都不是我自己想要的,终于找到种方法 如下: 1.声明两个属性 nickname是昵称的textfleld canEditSizeLAbel是提示用户剩 ...

  9. css样式 第6节

    程序员语录: 不要太刻意地把写程序这件事和挣钱挂起来,局限了你挣钱的本事 <html> <head> <title>网页样式</title> </ ...

  10. STUN/TURN/ICE协议在P2P SIP中的应用(一)

    1           说明 本文详细描述了基于STUN系列协议实现的P2P SIP电话过程,其中涉及到了SIP信令的交互,P2P的原理,以及STUN.TURN.ICE的协议交互 本文所提到的各个服务 ...