AC自动机+树链剖分+线段树/树状数组+dfs序+树链的并

题意:给出n个母串和q个询问串,对于每个询问串输出有多少个母串包含这个询问串 N=∑|母串|<=10^5 Q=∑|询问串|<=3.6*10^5

由于是母串包含询问串,那么我们就对询问串建自动机,然后用母串在上面跑,跑一次的复杂度是母串的长度(不确定)

利用fail树的性质求解,每次母串跑到一个节点,就把这个节点到根的路径都加上1,说明母串当前匹配单词的一段后缀包含某个前缀,也就是母串包含某个前缀

由于是求出现次数,那么询问串多次出现在母串里只算一次,所以之前到根的路径上加重了,所以我们利用树链的并去重,将节点按dfs序排序,相邻两个节点的lca到根的路径-1,这样就使得每个节点到根的路径都等于1

然后就真写了一个树链剖分+单点查询,其实直接查子树就行了,直接在节点上打上+1标记,lca上打上-1标记,树状数组维护子树和就行了

#include<bits/stdc++.h>
using namespace std;
const int N = ;
int n, q;
vector<char> v[N];
char s[N];
struct ac_automation {
int root, cnt, tot, dfs_clock;
int child[N][], fail[N], top[N], fa[N], son[N], dep[N], size[N], dfn[N], mir[N], tree[N << ], pos[N], tag[N << ];
vector<int> G[N], p;
void insert(char s[], int id)
{
int len = strlen(s), now = root;
for(int i = ; i < len; ++i)
{
int t = s[i] - 'a';
if(child[now][t] == ) child[now][t] = ++cnt;
now = child[now][t];
}
pos[id] = now;
}
void build_fail()
{
queue<int> q;
for(int i = ; i < ; ++i) if(child[root][i])
{
q.push(child[root][i]);
G[root].push_back(child[root][i]);
}
while(!q.empty())
{
int u = q.front();
q.pop();
for(int i = ; i < ; ++i)
{
int &v = child[u][i];
if(v == ) v = child[fail[u]][i];
else
{
fail[v] = child[fail[u]][i];
q.push(v);
G[child[fail[u]][i]].push_back(v);
}
}
}
}
int lca(int u, int v)
{
while(top[u] != top[v])
{
if(dep[top[u]] < dep[top[v]]) swap(u, v);
u = fa[top[u]];
}
return dep[u] < dep[v] ? u : v;
}
void dfs(int u)
{
size[u] = ;
for(int i = ; i < G[u].size(); ++i)
{
int v = G[u][i];
dep[v] = dep[u] + ;
fa[v] = u;
dfs(v);
size[u] += size[v];
if(size[v] >= size[son[u]]) son[u] = v;
}
}
void dfs(int u, int acs)
{
dfn[u] = ++dfs_clock;
mir[dfn[u]] = u;
top[u] = acs;
if(son[u]) dfs(son[u], acs);
for(int i = ; i < G[u].size(); ++i)
{
int v = G[u][i];
if(v == son[u]) continue;
dfs(v, v);
}
}
void pushdown(int x, int l, int r)
{
if(tag[x] == ) return;
int mid = (l + r) >> ;
tag[x << ] += tag[x];
tag[x << | ] += tag[x];
tree[x << ] += tag[x] * (mid - l + );
tree[x << | ] += tag[x] * (r - mid);
tag[x] = ;
}
int query(int l, int r, int x, int pos)
{
if(l == r) return tree[x];
pushdown(x, l, r);
int mid = (l + r) >> ;
if(pos <= mid) return query(l, mid, x << , pos);
else return query(mid + , r, x << | , pos);
}
void update(int l, int r, int x, int a, int b, int delta)
{
if(l > b || r < a) return;
if(l >= a && r <= b)
{
tag[x] += delta;
tree[x] += (r - l + ) * delta;
return;
}
pushdown(x, l, r);
int mid = (l + r) >> ;
update(l, mid, x << , a, b, delta);
update(mid + , r, x << | , a, b, delta);
tree[x] = tree[x << ] + tree[x << | ];
}
void change(int u, int delta)
{
while(top[u])
{
update(, cnt + , , dfn[top[u]], dfn[u], delta);
u = fa[top[u]];
}
update(, cnt + , , , dfn[u], delta);
}
void put_string(int id)
{
int len = v[id].size(), now = root;
p.clear();
for(int i = ; i < len; ++i)
{
now = child[now][v[id][i] - 'a'];
p.push_back(dfn[now]);
}
sort(p.begin(), p.end());
p.erase(unique(p.begin(), p.end()), p.end());
for(int i = ; i < p.size(); ++i)
{
int u = p[i];
change(mir[u], );
}
for(int i = ; i < p.size(); ++i)
{
int u = p[i], v = p[i - ];
change(lca(mir[u], mir[v]), -);
}
}
int ask(int id)
{
return query(, cnt + , , dfn[pos[id]]);
}
} ac;
int main()
{
scanf("%d%d", &n, &q);
for(int i = ; i <= n; ++i)
{
scanf("%s", s);
int len = strlen(s);
for(int j = ; j < len; ++j) v[i].push_back(s[j]);
}
for(int i = ; i <= q; ++i)
{
scanf("%s", s);
ac.insert(s, i);
}
ac.build_fail();
ac.dfs();
ac.dfs(, );
for(int i = ; i <= n; ++i) ac.put_string(i);
for(int i = ; i <= q; ++i) printf("%d\n", ac.ask(i));
return ;
}

bzoj2780的更多相关文章

  1. 【bzoj2780】 Sevenk Love Oimaster

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

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

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

  3. 【BZOJ2780】[Spoj]8093 Sevenk Love Oimaster 广义后缀自动机

    [BZOJ2780][Spoj]8093 Sevenk Love Oimaster Description Oimaster and sevenk love each other.     But r ...

  4. [bzoj2780][Spoj8093]Sevenk Love Oimaster_广义后缀自动机

    Sevenk Love Oimaster bzoj-2780 Spoj-8093 题目大意:给定$n$个大串和$m$次询问,每次给出一个字符串$s$询问在多少个大串中出现过. 注释:$1\le n\l ...

  5. BZOJ2780(广义后缀自动机,set启发式合并)

    BZOJ2780(广义后缀自动机,set启发式合并) 题面 自己找去 HINT 就是给多个文本串,然后每次查询的时候问你这个串在多少个文本串中出现过.因为多个文本串,那么直接就往广义后缀自动机上思考啊 ...

  6. BZOJ2780——[Spoj]8093 Sevenk Love Oimaster

    0.题意:给定N个原始字符串S,M次查询某个特殊的字符串S'在多少个原始串中出现过. 1.分析:这个题我们第一感觉就是可以用后缀自动机来搞,然后我们发现不是本质不同的字串..求出现过的次数,也就是说多 ...

  7. Bzoj2780: [Spoj]8093 Sevenk Love Oimaster

    题目 传送门 Sol 就是广义\(sam\) 然后记录下每个状态属于哪些串,开\(set\)维护 \(parent\)树上启发式合并一下就好了 # include <bits/stdc++.h& ...

  8. BZOJ2780:[SPOJ8093]Sevenk Love Oimaster(广义SAM)

    Description Oimaster and sevenk love each other. But recently,sevenk heard that a girl named ChuYuXu ...

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

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

  10. [BZOJ2780][SPOJ8093]Sevenk Love Oimaster

    bzoj luogu 题面 给定n个模板串,以及m个查询串. 依次查询每一个查询串是多少个模板串的子串. sol 广义后缀自动机裸题? 先建出\(SAM\),然后记录一下每个节点分别在多少个模板串里出 ...

随机推荐

  1. 12Oracle Database SQL程序

    Oracle Databse SQL 程序 程序块 在这之前,我们所有的sql语句都是一句一句执行的,如果我们把很多事情看作一个整体提交执行的话,必须使用程序块. 声明部分:声名变量及初始化 关键字: ...

  2. World Cup(The 2016 ACM-ICPC Asia China-Final Contest dfs搜索)

    题目: Here is World Cup again, the top 32 teams come together to fight for the World Champion. The tea ...

  3. JDK的下载---官方

    1.去到官方网站 http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 根据箭头选择, ...

  4. Python学习-字符串函数操作3

    字符串函数操作 isprintable():判断一个字符串中所有字符是否都是可打印字符的. 与isspace()函数很相似 如果字符串中的所有字符都是可打印的字符或字符串为空返回 True,否则返回 ...

  5. Win10中创建Hyper-V虚拟机

    Win10虚拟机创建方法方法 1 开始菜单->所有应用->Windows系统->控制面板,程序->启用或关闭Windows功能,勾选Hyper-V下所有选项 如果Hyper-V ...

  6. Boundary Conditions

    test test Table of Contents 1. Boundary conditions 1.1. Neumann boudary condition vs Dirichlet BC 1. ...

  7. linux下的进程

    一.进程的基础: 1.程序:程序是一些保存在磁盘上的指令的有序集合: 2.进程:进程是程序的一次执行过程: 3.进程与程序的关系:①.程序是静态的,进程是动态的:  ②.一个程序可以对应多个进程:   ...

  8. Android layer-list(3)

     Android layer-list(3) 在附录文章3.4的基础上,就Android layer-list再写一个较为复杂的应用. 先写布局文件,该布局涉及到LinearLayoutCompa ...

  9. noip模拟赛 铺瓷砖

    [问题描述]有一面很长很长的墙. 你需要在这面墙上贴上两行瓷砖. 你的手头有两种不同尺寸的瓷砖, 你希望用这两种瓷砖各贴一行.瓷砖的长可以用分数表示,贴在第一行的每块瓷砖长度为A/B贴在第二行的每块瓷 ...

  10. (13)Corner Detection角点检测

    import cv2 import numpy as np img=cv2.imread('opencv-corner-detection-sample.jpg') gray = cv2.cvtCol ...