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. leecode 每日解题思路 102-Binary Tree Level Order Traversal

    題目描述: 题目链接: 102-Binary Tree Level Order Traversal 这个问题要解决的是如何逐层遍历一个二叉树,并把同一层元素放入同一list中, 再将所有元素返回. 其 ...

  2. Objective-C语法快速参考(C# 和 Objective-C 语法的比较)

    大部分有一点其他平台开发基础的初学者看到XCode ,第一感想是磨拳擦掌,看到 Interface  Builder 之后,第一感想是跃跃欲试,而看到Objective-C 的语法,第一感想就变成就望 ...

  3. 构建简单的socket连接池

    一开始,选用Vector<E>来存放连接.由于这个容器不是并发安全的,于是,每个方法都加一个synchronized来保持并发时的同步操作,并发效率很差,果断放弃.空余时间研究了下多线程的 ...

  4. JavaScript入门(7)

    一.什么是函数 函数:把完成特定功能的代码放到一个函数里,直接调用这个函数,就省去重复输入大量代码的麻烦 函数的作用:写一次代码,然后反复地重用这个代码 Eg: 求多组数的和,不使用函数 { var ...

  5. postgresql 字符串拼接"||“的使用

    不过注意这里的只有postgresql可以使用,其他数据库不明. select name || remark as newname from mytable where name like '%tes ...

  6. 设置repeater每行多少个的方法

    前台代码: <asp:ScriptManagerProxy ID="ScriptManagerProxy1" runat="server">< ...

  7. 20160331javaweb之JSP 标签技术

    jsp的标签技术:在jsp页面中最好不要出现java代码,这时我们可以使用标签技术将java代码替换成标签来表示 1.jsp标签:sun原生提供的标签直接在jsp页面中就可以使用 <jsp:in ...

  8. 浅谈break 、continue、return,goto四种语句的区别。

    浅谈break .continue.return三种语句的区别: break,continue,return这三个具有跳转功能的语句在c语言中经常被用到,近期身边有些小伙伴总是把它们的用法搞乱,在这里 ...

  9. ios专题 - 委托模式实现

    在ios中,委托模式非常常见,那委托模式是什么? 委托模式是把一个对象把请求给另一个对象处理. 下面见例子: #import <UIKit/UIKit.h> @protocol LQIPe ...

  10. (hdu)1950 Bridging signals(最长上升子序列)

    Problem Description 'Oh no, they've done it again', cries the chief designer at the Waferland chip f ...