题面

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]);
}

最新文章

  1. 【转】App开放接口api安全性—Token签名sign的设计与实现
  2. 在list_*页面显示出一级栏目下的所有二级栏目
  3. 用crontab跑定时任务[转]
  4. Java创建WebService服务及客户端实现(转)
  5. eclipse连接外部tomcat进行debug
  6. 强类型DataSet的使用简明教程
  7. MVC控制器向View视图传值的三种方法
  8. bzoj2324营救皮卡丘
  9. 自动构建工具Ant的使用-笔记
  10. 100个iOS开发面试题汇总-王刚韧的技术博客
  11. .NET技术
  12. git 命令和使用场景总结
  13. 跨域问题实践总结!下( [HTML5] postMessage+服务器端(反向代理服务器+CORS Cross-Origin Resource Sharing))
  14. Python的几个爬虫代码整理(网易云、微信、淘宝、今日头条)
  15. JAVA接口里面的变量
  16. newwork setup
  17. [Android][Framework]裁剪SystemServer服务以及关闭SystemFeature
  18. UVA - 12716 - 异或序列
  19. anguar6中 无法在Element上找到属性 (eg 原DOM的offsetTop)
  20. android-support-v4.jar 免积分下载

热门文章

  1. RemoteFX
  2. Python框架之Django的相册组件
  3. BugKu 杂项-这么多数据包
  4. Format aborted in 格式化namenode 失败的原因
  5. Linux中date命令的各种实用方法
  6. 浅谈JavaScript中的函数问题
  7. bzoj1086【SCOI2005】王室联邦
  8. 【CCF】路径解析 模拟
  9. TCP面试题之为什么会有TIME_WAIT状态
  10. kubernetes 之容器监控