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

时间:2023-01-02 23:07:56

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. &lpar;RERERERERERERERERERERE&rpar; BZOJ 2746&colon; &lbrack;HEOI2012&rsqb;旅行问题

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

  2. BZOJ 2746&colon; &lbrack;HEOI2012&rsqb;旅行问题

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

  3. BZOJ2746&colon; &lbrack;HEOI2012&rsqb;旅行问题&lpar;AC自动机 LCA&rpar;

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

  4. BZOJ 2434&colon; &lbrack;Noi2011&rsqb;阿狸的打字机 &lbrack;AC自动机 Fail树 树状数组 DFS序&rsqb;

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

  5. BZOJ 3172&colon; &lbrack;Tjoi2013&rsqb;单词 &lbrack;AC自动机 Fail树&rsqb;

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

  6. BZOJ 2905&colon; 背单词 AC自动机&plus;fail树&plus;dfs序&plus;线段树

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

  7. BZOJ 2434&colon; &lbrack;Noi2011&rsqb;阿狸的打字机 AC自动机&plus;fail树&plus;线段树

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

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

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

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

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

随机推荐

  1. Bug避障算法简介

    移动机器人智能的一个重要标志就是自主导航,而实现机器人自主导航有个基本要求--避障.避障是指移动机器人根据采集的障碍物的状态信息,在行走过程中通过传感器感知到妨碍其通行的静态和动态物体时,按照一定的方 ...

  2. jQuery easyui 提示框

    1:弹出提示窗的使用 (1)屏幕右下弹出提示窗口: $.messager.show({ title:'My Title', msg:'Message will be closed after 4 se ...

  3. 第九十七节,使用JavaScript

    使用JavaScript 学习要点: 1.创建一张HTML页面 2.<Script>标签解析 3.JS代码嵌入的一些问题 一.创建一张HTML页面 因为JavaScript是嵌套在html ...

  4. 我为什么放弃使用MyBatis3的Mapper注解

    最近在使用MyBatis3做项目.在使用注解实现Mapper的时候遇到了比较奇葩的问题:在实现数据的batch insert的时候总是报错.好不容易可以正常插入了,但是又不能返回自增的主键id到实体b ...

  5. oracle复习(二)

    十一.replace 替换格式:(原字符串,要查找的字符或字符串,替换的字符或字符串)select replace('hello world','o','a') from dual; //替换时区分大 ...

  6. hdoj:2027

    #include <iostream> #include <string> #include <vector> using namespace std; int m ...

  7. 如何修改Git commit的信息

    原文地址: http://xiguada.org/change-git-commit-message   Git cimmit信息push后,如何修改,amend可以修改最后一次commit信息,但对 ...

  8. Java学习笔记七(目录操作)

    1.介绍 上一篇博客介绍的是java中经常使用的操作文件的方式,本篇博客着重解说一下,在Java中是怎样来操作目录的.主要是利用的是Java.IO包以下的File类,本篇博客着重解说一下该类的构造函数 ...

  9. BZOJ 1015:&lbrack;JSOI2008&rsqb;星球大战starwar(逆向处理&plus;并查集)

    [JSOI2008]星球大战starwar                                                时间限制: 3 Sec 内存限制: 162 MB[题目描述] ...

  10. BUPT复试专题—寻找第 K 小的数&lpar;2009&rpar;

    题目描述 给你 n 个完全不相同整数(n<=300),每一个数都大于 0 并且小于 1000,请找出 第 k 小的数. 输入 输入包括两行,第一行用空格隔开的两个数 n 和 k;第二行有 n 个 ...