题面

Description

Tom有n个字符串S1,S2...Sn,Jerry有一个字符串集合T,一开始集合是空的。

接下来会发生q个操作,操作有两种形式:

“1 P”,Jerry往自己的集合里添加了一个字符串P。

“2 x”,Tom询问Jerry,集合T中有多少个字符串包含串Sx。(我们称串A包含串B,当且仅当B是A的子串)

Jerry遇到了困难,需要你的帮助。

Input

第1行,一个数n;

接下来n行,每行一个字符串表示Si;

下一行,一个数q;

接下来q行,每行一个操作,格式见题目描述。

Output

对于每一个Tom的询问,帮Jerry输出答案。

Sample Input

3
a
bc
abc
5
1 abca
2 1
1 bca
2 2
2 3

Sample Output

1
2
1

HINT

100%: \(1≤N,Q≤100000\), \(\sum_{s \in S} |s|, \sum_{s \in T}|s| \le 2 \times 10^6\), \(alphabet = \{a ... z\}\)

Solution

正解貌似是fail树加树链的并, 但我写的是后缀树. 还没读入完空间就炸了... 先放一份代码吧

#include <cstdio>
#include <cstring>
#include <vector>
#define vector std::vector const int LEN = (int)2e6, N = (int)1e5, Q = (int)1e5;
int q;
int ans[Q];
struct segmentTree
{
struct node
{
node *suc[2];
int sz;
inline node() {for(int i = 0; i < 2; ++ i) suc[i] = NULL; sz = 0;}
}*rt;
inline segmentTree() {rt = NULL;}
node* insert(node *u, int L, int R, int pos)
{
if(u == NULL) u = new node;
if(L == R) {u->sz = 1; return u;}
if(pos <= L + R >> 1) u->suc[0] = insert(u->suc[0], L, L + R >> 1, pos); else u->suc[1] = insert(u->suc[1], (L + R >> 1) + 1, R, pos);
u->sz = 0;
for(int i = 0; i < 2; ++ i) if(u->suc[i] != NULL) u->sz += u->suc[i]->sz;
return u;
}
inline void insert(int pos) {rt = insert(rt, 1, q, pos);}
int query(node *u, int L, int R, int pos)
{
if(u == NULL) return 0;
if(R <= pos) return u->sz;
return query(u->suc[0], L, L + R >> 1, pos) + (pos > L + R >> 1 ? query(u->suc[1], (L + R >> 1) + 1, R, pos) : 0);
}
inline int query(int pos) {return query(rt, 1, q, pos);}
node* merge(int L, int R, node *u, node *_u)
{
if(u == NULL) return _u; if(_u == NULL) return u;
if(L == R) {u->sz |= _u->sz; delete _u; return u;}
u->suc[0] = merge(L, L + R >> 1, u->suc[0], _u->suc[0]); u->suc[1] = merge((L + R >> 1) + 1, R, u->suc[1], _u->suc[1]);
delete _u;
u->sz = 0;
for(int i = 0; i < 2; ++ i) if(u->suc[i] != NULL) u->sz += u->suc[i]->sz;
return u;
}
inline void merge(segmentTree *T) {rt = merge(1, q, rt, T->rt);}
};
struct suffixAutomaton
{
struct node
{
node *suc[26], *pre;
int len;
vector<int> bck, qry;
int vst;
vector<node*> successorOnSuffixTree;
inline node() {for(int i = 0; i < 26; ++ i) suc[i] = NULL; pre = NULL; vst = 0; bck.clear(); qry.clear(); successorOnSuffixTree.clear();}
}*rt;
inline suffixAutomaton() {rt = new node; rt->len = 0;}
inline node* insert(char *str, int len, int id)
{
node *lst = rt;
for(int i = 0; i < len; ++ i)
{
int c = str[i] - 'a';
if(lst->suc[c] != NULL)
{
node *p = lst->suc[c];
if(p->len == lst->len + 1) { if(~ id) p->bck.push_back(id); lst = p; continue;}
node *q = new node; if(~ id) q->bck.push_back(id);
for(int i = 0; i < 26; ++ i) q->suc[i] = p->suc[i]; q->pre = p->pre; q->len = lst->len + 1;
p->pre = q;
for(; lst != NULL && lst->suc[c] == p; lst = lst->pre) lst->suc[c] = q;
lst = q;
continue;
}
node *u = new node; u->len = lst->len + 1; if(~ id) u->bck.push_back(id);
for(; lst != NULL && lst->suc[c] == NULL; lst = lst->pre) lst->suc[c] = u;
if(lst == NULL) u->pre = rt;
else
{
node *p = lst->suc[c];
if(p->len == lst->len + 1) u->pre = p;
else
{
node *q = new node; for(int i = 0; i < 26; ++ i) q->suc[i] = p->suc[i]; q->pre = p->pre; q->len = lst->len + 1;
u->pre = p->pre = q;
for(; lst != NULL && lst->suc[c] == p; lst = lst->pre) lst->suc[c] = q;
}
}
lst = u;
}
return lst;
}
void build(node *u)
{
u->vst = 1; if(u->pre != NULL) u->pre->successorOnSuffixTree.push_back(u);
for(int i = 0; i < 26; ++ i) if(u->suc[i] != NULL && ! u->suc[i]->vst) build(u->suc[i]);
}
inline void buildSuffixTree() {build(rt);}
segmentTree* DFS(node *u)
{
segmentTree *seg = new segmentTree;
for(auto id : u->bck) seg->insert(id);
for(auto v : u->successorOnSuffixTree)
{
segmentTree *res = DFS(v);
seg->merge(res);
}
for(auto qry : u->qry) ans[qry] = seg->query(qry);
return seg;
}
inline void work() {DFS(rt);}
}SAM;
int main()
{ #ifndef ONLINE_JUDGE freopen("davljak.in", "r", stdin);
freopen("davljak.out", "w", stdout); #endif int n; scanf("%d\n", &n);
static char str[LEN];
static suffixAutomaton::node *ed[N + 1];
for(int i = 1; i <= n; ++ i) scanf("%s", str), ed[i] = SAM.insert(str, strlen(str), -1);
scanf("%d", &q);
for(int i = 1; i <= q; ++ i)
{
int opt; scanf("%d ", &opt);
if(opt == 1) scanf("%s", str), SAM.insert(str, strlen(str), i);
else if(opt == 2)
{
int x; scanf("%d", &x);
ed[x]->qry.push_back(i);
}
}
SAM.buildSuffixTree();
memset(ans, -1, sizeof(ans));
SAM.work();
for(int i = 1; i <= q; ++ i) if(~ ans[i]) printf("%d\n", ans[i]);
}

BZOJ 3881 COCI 2015 Divljak的更多相关文章

  1. [BZOJ 3745] [COCI 2015] Norma

    Description 给定一个正整数序列 \(a_1,a_2,\cdots,a_n\),求 \[ \sum_{i=1}^n\sum_{j=i}^n(j-i+1)\min(a_i,a_{i+1},\c ...

  2. bzoj 3743 [ Coci 2015 ] Kamp —— 树形DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3743 一开始想到了树形DP,处理一下子树中的最小值,向上的最小值,以及子树中的最长路和向上的 ...

  3. [LOJ 2134][UOJ 132][BZOJ 4200][NOI 2015]小园丁与老司机

    [LOJ 2134][UOJ 132][BZOJ 4200][NOI 2015]小园丁与老司机 题意 给定平面上的 \(n\) 个整点 \((x_i,y_i)\), 一共有两个问题. 第一个问题是从原 ...

  4. [LOJ 2133][UOJ 131][BZOJ 4199][NOI 2015]品酒大会

    [LOJ 2133][UOJ 131][BZOJ 4199][NOI 2015]品酒大会 题意 给定一个长度为 \(n\) 的字符串 \(s\), 对于所有 \(r\in[1,n]\) 求出 \(s\ ...

  5. [BZOJ 3992] [SDOI 2015] 序列统计(DP+原根+NTT)

    [BZOJ 3992] [SDOI 2015] 序列统计(DP+原根+NTT) 题面 小C有一个集合S,里面的元素都是小于质数M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数 ...

  6. [BZOJ 3930] [CQOI 2015]选数(莫比乌斯反演+杜教筛)

    [BZOJ 3930] [CQOI 2015]选数(莫比乌斯反演+杜教筛) 题面 我们知道,从区间\([L,R]\)(L和R为整数)中选取N个整数,总共有\((R-L+1)^N\)种方案.求最大公约数 ...

  7. 【BZOJ 3881】【COCI 2015】Divljak

    http://www.lydsy.com/JudgeOnline/problem.php?id=3881 好难的一道题啊qwq 一开始我想对T建AC自动机,根本不可做. 正解是对S建AC自动机. fa ...

  8. BZOJ 3881: [Coci2015]Divljak [AC自动机 树链的并]

    3881: [Coci2015]Divljak 题意:添加新文本串,询问某个模式串在多少种文本串里出现过 模式串建AC自动机,考虑添加一个文本串,走到的节点记录下来求树链的并 方法是按dfs序排序去重 ...

  9. BZOJ 3881: [Coci2015]Divljak

    3881: [Coci2015]Divljak Time Limit: 20 Sec  Memory Limit: 768 MBSubmit: 553  Solved: 176[Submit][Sta ...

随机推荐

  1. vue时时监听input输入框中 输入内容 写法

    Vue input 监听 使用 v-on:input="change" 实现即可 App.vue <template> <div> <md-field ...

  2. 了解Windows Server以及Hyper-V许可模式

    在2015年11月,微软宣布对Windows Server 2016以及Hyper-V的许可模式进行重大变更,并于2016年第三季度正式生效,Windows Server 2016标准版及数据中心版的 ...

  3. 我给女朋讲编程网络系列(2)--IIS8 如何在本地发布网站

    通过IIS8 在本地发布网站,一个截图,你就全明白了,越是简单,越是实用. 如果有现成的网站,就将你的网站放到一个文件夹中,比如WebTest2中. 如何没有网站,可以在WebTest2中新建一个in ...

  4. RSA进阶之低加密指数攻击

    适用场景: n很大,4000多位,e很小,e=3 一般来说,e选取65537.但是在RSA加密的时候有可能会选用e=3(不要问为什么,因为选取e =3省时省力,并且他可能觉得n在4000多位是很安全的 ...

  5. Java开发微信公众号(五)---微信开发中如何获取access_token以及缓存access_token

    获取access_token是微信api最重要的一个部分,因为调用其他api很多都需要用到access_token.比如自定义菜单接口.客服接口.获取用户信息接口.用户分组接口.群发接口等在请求的时候 ...

  6. RT-Thread学习之——静态线程和动态线程

    RT-Thread中支持静态和动态两种定义方式. 用线程来举例的话,rt_thread_init对应静态定义方式,rt_thread_create对应动态定义方式. 使用静态定义方式时,必须先定义静态 ...

  7. BZOJ 1051:[HAOI2006]受欢迎的牛(强连通分量)

    受欢迎的牛Description每一头牛的愿望就是变成一头最受欢迎的牛.现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎. 这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么 ...

  8. htmilunit-- 针对抓取js生成的数据

    public static String  getHtml(String html){        // 模拟一个浏览器          @SuppressWarnings("resou ...

  9. git 生成patch和打patch

    有这样的 目录层次 x/xx/xxx/xxx/ttt.c而 我的 当前位置 是在 x/下 ,执行git diff> test.patch 在test.patch补丁文件里的路径信息是这样的:- ...

  10. java的图像界面

    package test; import java.awt.FlowLayout; import java.awt.event.ActionListener; import java.awt.even ...