【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=3483

【题目大意】

  给出一些串,同时给出m对前缀后缀,询问有多少串满足给出的前缀后缀模式,
  题目要求强制在线

【题解】

  我们对于给出的每个字符串正着插入字典树A,倒着插入字典树B,
  对于一个前缀来说,在字典树A上得到的dfs序[st,en]就是所有的匹配串,
  同理,后缀在字典树B上dfs序[st,en]表示所有的后缀匹配串,
  同时满足两者的需提供二维查询,因此我们以Adfsn为版本,Bdfsn为下标建立可持久化线段树,
  查询版本间区间和的差值就是符合条件的答案。

【代码】

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
const int S=2000010,N=2010;
struct Trie{
int tot,dfn,st[S],en[S],son[S][26],ansL,ansR;
int Tr(char c){return c-'a';}
void Init(){
for(int i=0;i<=tot;i++)for(int j=0;j<26;j++)son[i][j]=0;
dfn=tot=0;
}
int insert(char *s){
int x=0;
for(int l=strlen(s),i=0;i<l;i++){
if(!son[x][Tr(s[i])])son[x][Tr(s[i])]=++tot;
x=son[x][Tr(s[i])];
}return x;
}
void dfs(int x){
st[x]=++dfn;
for(int i=0;i<26;i++)if(son[x][i])dfs(son[x][i]);
en[x]=dfn;
}
void ask(char *s){
int x=0;
for(int l=strlen(s),i=0;i<l;i++){
if(!son[x][Tr(s[i])]){ansL=ansR=0;return;}
x=son[x][Tr(s[i])];
}ansL=st[x],ansR=en[x];
}
}A;
struct RevTrie{
int tot,dfn,st[S],en[S],son[S][26],ansL,ansR;
int Tr(char c){return c-'a';}
void Init(){
for(int i=0;i<=tot;i++)for(int j=0;j<26;j++)son[i][j]=0;
dfn=tot=0;
}
int insert(char *s){
int x=0;
for(int l=strlen(s),i=l-1;i>=0;i--){
if(!son[x][Tr(s[i])])son[x][Tr(s[i])]=++tot;
x=son[x][Tr(s[i])];
}return x;
}
void dfs(int x){
st[x]=++dfn;
for(int i=0;i<26;i++)if(son[x][i])dfs(son[x][i]);
en[x]=dfn;
}
void ask(char *s){
int x=0;
for(int l=strlen(s),i=l-1;i>=0;i--){
if(!son[x][Tr(s[i])]){ansL=ansR=0;return;}
x=son[x][Tr(s[i])];
}ansL=st[x],ansR=en[x];
}
}B;
namespace Persistent_Segment_Tree{
int l[N*40],r[N*40],v[N*40],tot,root[S];
int change(int x,int a,int b,int c,int p){
int y=++tot;v[y]=v[x]+p;
if(a==b)return y;
int mid=(a+b)>>1;
if(c<=mid)l[y]=change(l[x],a,mid,c,p),r[y]=r[x];
else l[y]=l[x],r[y]=change(r[x],mid+1,b,c,p);
return y;
}
int query(int x,int a,int b,int c,int d){
if(!x)return 0;
if(c<=a&&b<=d)return v[x];
int mid=(a+b)>>1,res=0;
if(c<=mid)res+=query(l[x],a,mid,c,d);
if(d>mid)res+=query(r[x],mid+1,b,c,d);
return res;
}
};
int n,m,posa[N],posb[N];
char s[S];
vector<int> G[S];
int main(){
using namespace Persistent_Segment_Tree;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf(" %s",s);
posa[i]=A.insert(s);
posb[i]=B.insert(s);
}
A.dfs(0); B.dfs(0);
for(int i=1;i<=n;i++)G[A.st[posa[i]]].push_back(B.st[posb[i]]);
for(int i=1;i<=A.dfn;i++){
root[i]=root[i-1];
for(int j=0;j<G[i].size();j++)root[i]=change(root[i],1,B.dfn,G[i][j],1);
}
int ans=0;
scanf("%d",&m);
while(m--){
scanf(" %s",s);
int len=strlen(s);
for(int i=0;i<len;i++)s[i]=(s[i]-'a'+ans)%26+'a';
A.ask(s);
scanf(" %s",s);
len=strlen(s);
for(int i=0;i<len;i++)s[i]=(s[i]-'a'+ans)%26+'a';
B.ask(s);
if(A.ansL&&B.ansL)ans=query(root[A.ansR],1,B.dfn,B.ansL,B.ansR)-query(root[A.ansL-1],1,B.dfn,B.ansL,B.ansR);
else ans=0;
printf("%d\n",ans);
}return 0;
}

BZOJ 3483 SGU505 Prefixes and suffixes(字典树+可持久化线段树)的更多相关文章

  1. 主席树||可持久化线段树+离散化 || 莫队+分块 ||BZOJ 3585: mex || Luogu P4137 Rmq Problem / mex

    题面:Rmq Problem / mex 题解: 先离散化,然后插一堆空白,大体就是如果(对于以a.data<b.data排序后的A)A[i-1].data+1!=A[i].data,则插一个空 ...

  2. [BZOJ 4771]七彩树(可持久化线段树+树上差分)

    [BZOJ 4771]七彩树(可持久化线段树+树上差分) 题面 给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色,其中第i个节点的颜色为c[i].如果c[i] ...

  3. [BZOJ 3207] 花神的嘲讽计划Ⅰ【Hash + 可持久化线段树】

    题目链接:BZOJ - 3207 题目分析 先使用Hash,把每个长度为 k 的序列转为一个整数,然后题目就转化为了询问某个区间内有没有整数 x . 这一步可以使用可持久化线段树来做,虽然感觉可以有更 ...

  4. BZOJ.4771.七彩树(可持久化线段树)

    BZOJ 考虑没有深度限制,对整棵子树询问怎么做. 对于同种颜色中DFS序相邻的两个点\(u,v\),在\(dfn[u],dfn[v]\)处分别\(+1\),\(dfn[LCA(u,v)]\)处\(- ...

  5. BZOJ.3218.a + b Problem(最小割ISAP 可持久化线段树优化建图)

    BZOJ UOJ 首先不考虑奇怪方格的限制,就是类似最大权闭合子图一样建图. 对于奇怪方格的影响,显然可以建一条边\((i\to x,p_i)\),然后由\(x\)向\(1\sim i-1\)中权值在 ...

  6. BZOJ - 2588 Spoj 10628. Count on a tree (可持久化线段树+LCA/树链剖分)

    题目链接 第一种方法,dfs序上建可持久化线段树,然后询问的时候把两点之间的所有树链扒出来做差. #include<bits/stdc++.h> using namespace std; ...

  7. BZOJ 3439 Kpm的MCpassword Trie树+可持久化线段树

    题目大意:给定n个字符串,对于每一个字符串求以这个字符串为后缀的字符串中第k小的编号 首先将字符串反转 那么就变成了对于每一个字符串求以这个字符串为前缀的字符串中第k小的编号 然后考虑对字符串排序 那 ...

  8. BZOJ 4771: 七彩树 可持久化线段树+树链的并

    这个思路挺有意思的 ~ 利用树链的并来保证每个颜色只贡献一次,然后用可持久化线段树维护 code: #include <set> #include <cstdio> #incl ...

  9. 归并树 划分树 可持久化线段树(主席树) 入门题 hdu 2665

    如果题目给出1e5的数据范围,,以前只会用n*log(n)的方法去想 今天学了一下两三种n*n*log(n)的数据结构 他们就是大名鼎鼎的 归并树 划分树 主席树,,,, 首先来说两个问题,,区间第k ...

随机推荐

  1. SQLServer 学习相关资料整理【转】

    存储过程: SQL Server 存储过程 博客园上的一篇文章,讲解的非常详细,有测试代码,很实用. sqlserver存储过程中执行动态sql语句  The Curse and Blessings ...

  2. imperva 默认策略添加例外

    创建违规访问 检查违规的告警类型 假如客户的这个目录下真的有这个文件,而且客户非常明确这是一个正常且安全的东西怎么办?我该如何的将它添加到例外? 添加例外的步骤: 再次构造违规的请求: 默认策略添加例 ...

  3. linux用户权限 -> 系统基本权限

    比如rwxr-xr-x linux中正是这9个权限位来控制文件属主(User).属组(Group).其他用户(Other)基础权限. 用户对资源来说, 有三种角色 User(u): 属主用户(文件所有 ...

  4. java基础70 负责静态的网页制作语言XML(网页知识)

    HTML:负责网页结构的CSS:负责网页的样式(美观)JavaScript:负责客户(浏览器)端与用户进行交互 1.HTML语言的特点 1.由标签组成    2.语法结构松散     3.大小写不区分 ...

  5. java 学习网站

    http://how2j.cn/  教学网站 慕课视频下载网站 http://www.feemic.cn/mooc //慕课搜索和下载的网站http://www.soshoulu.com/tools/ ...

  6. 【转载】pygame的斜线运动

    pygame是用来写2D游戏的. 实现斜线运动,无非是在x和y两个方向上分运动的合成.x方向上的运动,当撞到边界的时候取相反速度就好了. 这里是用网球王子中的图片,以及一个网球实现,效果截图: 注意看 ...

  7. C/C++经典面试题

    1.指向数组的指针 和 指向数组首元素的指针 2018-03-07 昨天在牛客上看到这么一道C语言面试题,挺经典的,特来分享给大家. 程序如下,问输出结果 #include <stdio.h&g ...

  8. N皇后问题的实现

    N皇后问题是一个经典的问题,是回溯算法的典型案例.它是由国际西洋棋棋手马克斯·贝瑟尔于1848年提出的八皇后问题延伸而来的,具体要求如下:在N*N的方格棋盘放置N个皇后,使她们彼此不相互攻击,即任意2 ...

  9. 一行代码实现Okhttp,Retrofit,Glide下载上传进度监听

    https://mp.weixin.qq.com/s/bopDUFMB7EiK-MhLc3KDXQ essyan 鸿洋 2017-06-29 本文作者 本文由jessyan投稿. jessyan的博客 ...

  10. Redis(二)CentOS7安装Redis4.0.10与集群搭建

    一 Redis单机安装 1 Redis下载安装 1.1 检查依赖环境(Redis是C语言开发,编译依赖gcc环境) [root@node21 redis-]$ gcc -v -bash: gcc: c ...