http://www.spoj.com/problems/JZPGYZ/

查询一个询问串在上面n个串中多少个串的子串。

后缀数组+主席树,常熟有点大。。。

建出广义SAM,利用parent树的dfs序,每次相当于询问parent树的一个子树中出现了多少不同的颜色。

可以用主席树统计,pre表示dfs序上与这个位置属于同一个串的前一个位置在哪,主席树询问区间内的pre小于这个区间左端点的个数(也就是不同的颜色数)。

或者更方便地,把每个询问拆成parent树dfs序上的两个前缀和相减。

离线排序前缀和从左到右用bits维护pre为权值的树状数组并且查询小于某个区间左端点的pre的个数,统计答案时做一下减法就可以了(类似主席树)。

时间复杂度\(O(n\log n)\)。

还有不科学的暴力的做法,对于n个模板串,暴力在parent树上打标记,时间复杂度\(O(n^2)\)。

数据并没有卡这种做法。于是我本着复习广义后缀自动机的原则(和懒得写bits的原则),只写了这种暴力的做法。。。

将近花了一天重新脑补了一下广义SAM,感觉以前直接套用普通SAM的插入模板导致多出来了一些点不美观(当然多出来的这些点都可以合并到它们的parent),就重写了一下不会多出来点的广义SAM模板,常数更大,代码更长qwq,但保证所有节点的Right集合都是它们parent的Right集合的真子集(及不用费心想着哪些点可以合并在一起了)。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; const int N = 360003; char s[N];
int l[N], r[N]; struct State {
State *par, *go[50];
int val, tim, cnt;
State(int _num) : val(_num) {
par = 0; tim = cnt = 0;
memset(go, 0, sizeof(go));
}
} *root, *last; void extend(int w) {
if (last->go[w] && last->go[w]->val == last->val + 1) {last = last->go[w]; return;}
State *p = last;
State *np = new State(p->val + 1);
while (p && p->go[w] == 0)
p->go[w] = np, p = p->par;
if (p == 0) np->par = root;
else {
State *q = p->go[w];
if (q->val == p->val + 1) np->par = q;
else if (p != last) {
State *nq = new State(p->val + 1);
memcpy(nq->go, q->go, sizeof(q->go));
nq->par = q->par; q->par = np->par = nq;
while (p && p->go[w] == q)
p->go[w] = nq, p = p->par;
} else {
memcpy(np->go, q->go, sizeof(q->go));
np->par = q->par; q->par = np;
while (p && p->go[w] == q)
p->go[w] = np, p = p->par;
}
}
last = np;
} void mark(State *t, int timing) {
if (t == root || t->tim == timing) return;
t->tim = timing; ++t->cnt;
mark(t->par, timing);
} int n, m; int main() {
root = new State(0);
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) {
l[i] = r[i - 1] + 1;
scanf("%s", s + l[i]);
r[i] = l[i] + strlen(s + l[i]) - 1;
} for (int i = 1; i <= n; ++i) {
last = root;
for (int j = l[i], top = r[i]; j <= top; ++j)
extend(s[j] - 'a');
} State *tmp;
for (int i = 1; i <= n; ++i) {
tmp = root;
for (int j = l[i], top = r[i]; j <= top; ++j) {
tmp = tmp->go[s[j] - 'a'];
mark(tmp, i);
}
} int len; bool flag;
for (int i = 1; i <= m; ++i) {
scanf("%s", s);
len = strlen(s);
tmp = root; flag = true;
for (int j = 0; j < len; ++j)
if (tmp->go[s[j] - 'a'])
tmp = tmp->go[s[j] - 'a'];
else {
flag = false;
break;
}
if (!flag) puts("0");
else printf("%d\n", tmp->cnt);
}
return 0;
}

【SPOJ 8093】Sevenk Love Oimaster的更多相关文章

  1. SPOJ 8093 JZPGYZ - Sevenk Love Oimaster

    思路 可以用复杂度不对的做法水过去 相当于求parent树子树中的颜色种数,可以离线后树状数组(HH的项链,询问右端点排序之后维护last),dsu on tree,莫队都可以 但是也可以记录每个点上 ...

  2. 【BZOJ2780】【SPOJ】Sevenk Love Oimaster(后缀自动机)

    [BZOJ2780][SPOJ]Sevenk Love Oimaster(后缀自动机) 题面 BZOJ 洛谷 题解 裸的广义后缀自动机??? 建立广义后缀自动机建立出来之后算一下每个节点被几个串给包括 ...

  3. 【 SPOJ - GRASSPLA】 Grass Planting (树链剖分+树状数组)

    54  种草约翰有 N 个牧场,编号为 1 到 N.它们之间有 N − 1 条道路,每条道路连接两个牧场.通过这些道路,所有牧场都是连通的.刚开始的时候,所有道路都是光秃秃的,没有青草.约翰会在一些道 ...

  4. 【bzoj2780】 Sevenk Love Oimaster

    http://www.lydsy.com/JudgeOnline/problem.php?id=2780 (题目链接) 题意 给出很多主串和很多询问串,求一个询问串在多少主串中出现过 Solution ...

  5. 【BZOJ2780】Sevenk Love Oimaster【广义后缀自动机】

    题意 给出你n个字符串和q个查询,每个查询给出一个字符串s,对于每个查询你都要输出这个字符串s在上面多少个字符串中出现过. 分析 广义后缀自动机的裸题.建好SAM以后再跑一遍得到每个状态的ocu和la ...

  6. 【SPOJ 2319】 BIGSEQ - Sequence (数位DP+高精度)

    BIGSEQ - Sequence You are given the sequence of all K-digit binary numbers: 0, 1,..., 2K-1. You need ...

  7. 【SPOJ 694】Distinct Substrings (更直接的求法)

    [链接]h在这里写链接 [题意] 接上一篇文章 [题解] 一个字符串所有不同的子串的个数=∑(len-sa[i]-height[i]) [错的次数] 0 [反思] 在这了写反思 [代码] #inclu ...

  8. 【SPOJ 694】Distinct Substrings

    [链接]h在这里写链接 [题意]     给你一个长度最多为1000的字符串     让你求出一个数x,这个x=这个字符串的不同子串个数; [题解]     后缀数组题.     把原串复制一份,加在 ...

  9. 【SPOJ DQUERY】区间数字统计

    [链接] 我是链接,点我呀:) [题意] 题意 [题解] 因为区间的端点移动一个单位的话,只会涉及到一个元素的增多或减少. 因此可以用莫队算法来解决. 只需要开一个数组(大小1百万),用下标来快速检索 ...

随机推荐

  1. 【NOIP】2013提高组 花匠(摆花)

    [算法]DP||贪心 [题解] (1)动态规划: 令f[i][0..1]为两种条件下前i株花的最大保留数量,状态转移方程: f[i][0]=max(f[j][1]+1) (j=i-1...1)(h[i ...

  2. js基础知识点收集

    js基础知识点收集 js常用基本类型 function show(x) { console.log(typeof(x)); // undefined console.log(typeof(10)); ...

  3. linux系统环境 ——(四)

    默认有6个命令交互通道和一个图形界面交互通道,默认进入到的是图形界面通道 命令交互模式切换:ctrl+alt+f1---f6 图形交互界面 ctrl+alt+f7 1.图形界面交互模式 - termi ...

  4. PKUWC 2019 自闭记

    PKUWC 2019 自闭记 Day -1 考前天天在隔壁的物竞教室划水(雀魂,能和吉老师一起玩的游戏都是好游戏),没有做题. Day 0 早上8:16的高铁,到广州南居然要6个小时...不知道福州和 ...

  5. GDB实战

    程序中除了一目了然的Bug之外都需要一定的调试手段来分析到底错在哪.到目前为止我们的调试手段只有一种:根据程序执行时的出错现象假设错误原因,然后在代码中适当的位置插入 printf ,执行程序并分析打 ...

  6. TCP之listen&backlog

    1. listen函数: #include <sys/socket.h> int listen(int sockfd, int backlog); ret-成功返回0 失败返回- list ...

  7. JS函数和变量名称冲突

    在JS中如果函数名与变量名冲突,JS是怎么执行的? <script> console.log(sum);//function sum(){} function sum(){} var su ...

  8. 如何设置static tableview的section区域高度

    重写代理方法- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { i ...

  9. WordPress个人博客搭建

    搭建LNMP环境 请参考前面的博文自行搭建 部署WordPress #创建数据库和用户 mysql -uroot -p123456 -S /data/3306/mysql.sock create da ...

  10. PHP的命名空间namespace

    对于命名空间,官方文档已经说得很详细[查看],我在这里做了一下实践和总结. 命名空间一个最明确的目的就是解决重名问题,PHP中不允许两个函数或者类出现相同的名字,否则会产生一个致命的错误.这种情况下只 ...