51nod 小Z的trie(Trie+广义SAM)
【题目链接】
http://www.51nod.com/contest/problem.html#!problemId=1647
【题意】
给定一个n个字符串的Trie,每次询问一个字符串在Trie上的出现次数。
【思路】
将n个字符串构造一个Trie,构造广义后缀自动机,识别Trie中的所有子串。
则问题转化为求子串[l,r]在所属字符串中的出现次数,和 这道题 类似,采用树上倍增得到|right|的方法。
比较恶心的是定位字符串的位置=-=。
【代码】
#include<set>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
#define rep(a,b,c) for(int a=(b);a>=(c);a--)
using namespace std; typedef long long ll;
const int N = 1e6+;
const int D = ;
const int maxnode = ; int pos[N],pos2[N],cur; ll read() {
char c=getchar();
ll f=,x=;
while(!isdigit(c)) {
if(c=='-') f=-; c=getchar();
}
while(isdigit(c))
x=x*+c-'',c=getchar();
return x*f;
} struct SAM
{
int sz,fa[maxnode],mx,ch[maxnode][],l[maxnode];
int siz[maxnode],b[maxnode],c[N],fat[maxnode][D];
SAM() {
sz=;
memset(l,,sizeof(l));
memset(siz,,sizeof(siz));
}
int add(int c,int p) {
int np=++sz; l[np]=l[p]+;
mx=max(mx,l[np]); siz[np]=;
for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
if(!p) fa[np]=;
else {
int q=ch[p][c];
if(l[q]==l[p]+) fa[np]=q;
else {
int nq=++sz; l[nq]=l[p]+;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q];
fa[np]=fa[q]=nq;
for(;q==ch[p][c];p=fa[p]) ch[p][c]=nq;
}
}
return np;
}
void get_pre() {
FOR(i,,sz) c[l[i]]++;
FOR(i,,mx) c[i]+=c[i-];
FOR(i,,sz) b[c[l[i]]--]=i;
rep(i,sz,) siz[fa[b[i]]]+=siz[b[i]];
FOR(j,,sz) {
int i=b[j]; //按照拓扑序递推fat
fat[i][]=fa[i];
FOR(j,,D-)
fat[i][j]=fat[fat[i][j-]][j-];
}
}
int solve(int u,int len) {
rep(i,D-,)
if(l[fat[u][i]]>=len) u=fat[u][i];
return siz[u];
}
} sam; struct Node {
int id,np;
};
struct Trie
{
int sz,ch[N][];
queue<Node> q;
Trie() {
sz=;
memset(ch,,sizeof(ch));
}
void insert(char* s) {
int u=;
for(int i=;s[i];i++) {
int c=s[i]-'a';
if(!ch[u][c]) ch[u][c]=++sz;
u=ch[u][c]; pos[++cur]=u;
}
}
void bfs() {
int u=;
q.push((Node){u,});
while(!q.empty()) {
Node qr=q.front(); q.pop();
int u=qr.id,p=qr.np;
FOR(c,,) if(ch[u][c]) {
int v=ch[u][c];
int np=sam.add(c,p);
pos2[v]=np;
q.push((Node){v,np});
}
}
}
} trie; int n,m,len[N];
char s[N]; int main()
{
n=read();
FOR(i,,n) {
scanf("%s",s);
len[i]=len[i-]+strlen(s);
trie.insert(s);
}
trie.bfs();
sam.get_pre();
scanf("%d",&m);
int p,x,y;
while(m--) {
p=read(),x=read(),y=read();
x+=len[p-],y+=len[p-];
printf("%d\n",sam.solve(pos2[pos[y]],y-x+));
}
return ;
}
51nod 小Z的trie(Trie+广义SAM)的更多相关文章
- BZOJ3926 ZJOI2015 诸神眷顾的幻想乡 Trie、广义SAM
传送门 树上的任意一条路径一定会在以某一个叶子节点为根的树上成为一条直上直下的链,而总共只有\(20\)个叶子节点. 于是每一次选所有叶子节点中的一个作为根,形成一个\(Trie\),把\(20\)个 ...
- 【bzoj5084】 hashit(广义SAM+set)
题面 传送门 题解 后缀平衡树是个啥啊我不会啊-- 那么我们来考虑一下\(SAM\)的做法好了 不难发现它的本义是要我们维护一棵\(trie\)树,并求出\(trie\)树上每一个节点到根的这段串的不 ...
- 关于SAM和广义SAM
关于SAM和广义SAM 不是教程 某些思考先记下来 SAM 终于学会了这个东西诶...... 一部分重要性质 确定一个重要事情,S构造出的SAM的一个重要性质是当且仅当对于S的任意一个后缀,可以从1号 ...
- 【BZOJ 3926】 [Zjoi2015]诸神眷顾的幻想乡 (广义SAM)
3926: [Zjoi2015]诸神眷顾的幻想乡 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 974 Solved: 573 Descriptio ...
- 【20170920校内模拟赛】小Z爱学习
所有题目开启-O2优化,开大栈空间,评测机效率为4亿左右. T1 小 Z 学数学(math) Description 要说小 Z 最不擅长的学科,那一定就是数学了.这不,他最近正在学习加法运算.老 ...
- luogu3346 诸神眷顾的幻想乡 (广义SAM)
首先,让每一个叶节点做一次树根的话,每个路径一定至少有一次会变成直上直下的 于是对于每个叶节点作为根产生的20个trie树,把它们建到同一个广义SAM里 建法是对每个trie dfs去建,last就是 ...
- BZOJ3926:[ZJOI2015]诸神眷顾的幻想乡(广义SAM)
Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看. ...
- YbtOJ#532-往事之树【广义SAM,线段树合并】
正题 题目链接:https://www.ybtoj.com.cn/problem/532 题目大意 给出\(n\)个点的一个\(Trie\)树,定义\(S_x\)表示节点\(x\)代表的字符串 求$$ ...
- 广义SAM
参考 还有首先你要会SAM吧~ 用途 相比与单串SAM,广义自动机能存储的是多个字符串. 有两种写法,第一种是离线利用trie树结构,第二种是在线伪广义SAM 离线+Trie 首先构建出trie树. ...
随机推荐
- 第二次结对作业-WordCount进阶需求
原博客 队友博客 github项目地址 目录 具体分工 需求分析 PSP表格 解题思路描述与设计实现说明 爬虫使用 代码组织与内部实现设计(类图) 算法的关键与关键实现部分流程图 附加题设计与展示 设 ...
- Prism框架的优点
以我粗略的了解,prism/mvvm可以做到完全的逻辑和ui分离.即便是事件都是如此.这是主要优点.mvc是从本质上ui框架(当前大量半吊子把业务逻辑写在里面是不对的),mvvm包含客户端的业务逻辑. ...
- JMeter性能测试基础 (2) - 变量的使用
在使用JMeter进行性能测试时,一般情况下要保证样本容量尽可能大,这样才能得到一个比较合理的结果.也就是说,我们不能只对同一个URL进行多次访问,而是要对统一模块下尽可能多的URL进行访问,以取得相 ...
- windows多线程(六) 互斥量Mutex与关键段CriticalSection比较
一.关键段CS 和 互斥量Mutex 的相同点:都有线程拥有权 关键段和互斥量都有线程拥有权,即可以被一个线程拥有.在 前面讲关键段CS的文章中有说到,关键段结构体的第四个参数保存着拥有该关键段的线程 ...
- LInux查看网速带宽及各进程占用情况:nethogs
安装: #Ubuntu: sudo apt-get install nethogs #CentOS: sudo yum install nethogs 使用: $ sudo nethogs
- Android Studio系列教程
Android Studio系列教程 Android Studio系列教程一 —- 下载与安装 Android Studio系列教程二 —- 基本设置与运行 Android Studio系列教程三 — ...
- 第211天:git和github的区别和使用详解
一.git 1.什么是git 它是一个源代码管理工具,在一个项目中,凡是由开发人员编写的都算是源代码,源代码有必要管理起来,让源代码可以被追溯,主要记录每次变更了什么,谁主导这次变化.人为的维护比较麻 ...
- Qt——数据库编程
一.概述 Qt提供了一个类似JDBC的数据库接口,需要为每个可以连接的特定数据库提供驱动程序,可以通过 QStringList QSqlDatabase::drivers() 知道当前版本的Qt哪些驱 ...
- DAY...
讲道理,我还是以前的我.没有坚持每天写......... 又到了谷底......... 坚持啊........
- Java8 新特性Stream 的学习和使用方法
流(Stream) 流是java 8 中新引入的特性,用来处理集合中的数据,Stream 是一个来自数据源的元素队列并支持聚合操作. Java 中 Stream 不会存储元素. 数据源 流的来源. 可 ...