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. 【BZOJ4817】【SDOI2017】树点涂色 [LCT][线段树]

    树点涂色 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description Bob有一棵n个点的有根树,其中1 ...

  2. 51nod1667 概率好题

    基准时间限制:4 秒 空间限制:131072 KB 分值: 640  甲乙进行比赛. 他们各有k1,k2个集合[Li,Ri] 每次随机从他们拥有的每个集合中都取出一个数 S1=sigma甲取出的数,S ...

  3. gridveiw的使用

    using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.UI ...

  4. js删除数组中重复的元素

    1.方法一 将数组逐个搬到另一个数组中,当遇到重复元素时,不移动,若元素不重复则移动到新数组中 function unique(arr){ var len = arr.length; var resu ...

  5. SSH 登录失败:Host key verification failed 的处理方法

    原因就是你之前已经登录过这个服务器了然后改系统啥的了.导致目标主机 key 值不正确.直接把本机的key文件删除即可 sudo rm /home/yourname/.ssh/known_hosts

  6. Linux 入门记录:九、Linux 文件系统挂载管理

    一.挂载操作 磁盘或分区创建好文件系统后,需要挂载到一个目录才能够使用. Windows 或 Mac 系统会进行自动挂载,一旦创建好文件系统后会自动挂载到系统上,Windows 上称之为 C 盘.D ...

  7. Open Compute Project

    Open Compute Project https://github.com/opencomputeproject https://github.com/floodlight/floodlight ...

  8. WA时查错点

    这篇文章旨在总结可能出错的原因,想到时随时会补充. 查看调试输出语句是否删除 查看数组是否清零 查看是否使用long long 查看是否有的常量应开LL(如1LL << (32) ) 查看 ...

  9. 2017多校第5场 HDU 6085 Rikka with Candies bitset

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6085 题意:存在两个长度为n,m的数组A,B.有q个询问,每个询问有一个数字k,可以得到Ai%Bj=k ...

  10. Pylot网站Web服务器性能和负载压力测试-适用Windows可绘制图表

    为了能够准确地评估网站服务器对网络流量的承受能力,我们一般会采取模拟网站用户访问,通过不断地增加并发数,延长访问时长,从而最终得出网站Web服务器的性能和负载能力.当然也可以通过Web压力测试,来完善 ...