博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[NOI 2011]阿狸的打字机
阅读量:5056 次
发布时间:2019-06-12

本文共 3451 字,大约阅读时间需要 11 分钟。

Description

给你 \(n\) 个单词, \(m\) 组询问,每组询问形同 \((x,y)\) ,询问 \(x\) 串在 \(y\) 串中出现多少次。

\(1\leq n,m\leq10^5\)

Solution

比较暴力的做法就是建好 \(AC\) 自动机后,对于每个 \(y\) 串暴力跑一遍。看看查询的时候有多少次落在了 \(x\) 串的末尾。

我们可以构建 \(fail\) 树,那么其实题目可以转变为对于 \(x\) 串末尾节点,其子树中有多少个节点位于 \(y\) 串上。

由于题目的特殊性,我们可以离线询问按照 \(y\) 来排序。并且预处理出 \(AC\) 自动机的 \(dfn\)

我们按照构建 \(Trie\) 树的操作再按原字符串走一遍。入栈时对应的 \(dfn\)\(+1\) ,出时对应的 \(dfn\)\(-1\) 。那么走到一个单词节点,所有打上标记的 \(dfn\) 都是该单词上的。

注意到一个子树内的 \(dfn\) 都是连续的,显然就可以回答所有 \(y\) 等于该单词的询问了。树状数组维护 \(dfn\) 的标记的前缀和即可。

Code

//It is made by Awson on 2018.3.18#include 
#define LL long long#define dob complex
#define Abs(a) ((a) < 0 ? (-(a)) : (a))#define Max(a, b) ((a) > (b) ? (a) : (b))#define Min(a, b) ((a) < (b) ? (a) : (b))#define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))#define writeln(x) (write(x), putchar('\n'))#define lowbit(x) ((x)&(-(x)))using namespace std;const int N = 100000;void read(int &x) { char ch; bool flag = 0; for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar()); for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar()); x *= 1-2*flag;}void print(int x) {if (x > 9) print(x/10); putchar(x%10+48); }void write(int x) {if (x < 0) putchar('-'); print(Abs(x)); }char ch[N+5];int n, m, idx, dfn[N+5], size[N+5], ans[N+5], mp[N+5];struct tt {int to, next; }edge[(N<<1)+5];struct qu { int x, y, id; bool operator < (const qu &b) const {return y < b.y; }}que[N+5];int path[N+5], top;void add(int u, int v) {edge[++top].to = v, edge[top].next = path[u], path[u] = top; }struct bittree { int c[N+5]; void add(int o, int val) {for (; o <= idx; o += lowbit(o)) c[o] += val; } int count(int o) {int ans = 0; for (; o; o -= lowbit(o)) ans += c[o]; return ans; }}BT;struct Trie { int ch[N+5][26], pre[N+5], f[N+5], val[N+5], pos; void build(char *S) { int u = 0; for (int i = 0, len = strlen(S); i < len; i++) { if (S[i] == 'P') {val[u] = ++n, mp[n] = u; continue; } if (S[i] == 'B') {u = pre[u]; continue; } if (ch[u][S[i]-'a'] == 0) ++pos, pre[pos] = u, ch[u][S[i]-'a'] = pos; u = ch[u][S[i]-'a']; } } void get_fail() { queue
Q; for (int i = 0; i < 26; i++) if (ch[0][i]) f[ch[0][i]] = 0, Q.push(ch[0][i]); while (!Q.empty()) { int u = Q.front(); Q.pop(); for (int i = 0; i < 26; i++) { if (ch[u][i]) f[ch[u][i]] = ch[f[u]][i], Q.push(ch[u][i]); else ch[u][i] = ch[f[u]][i]; } } for (int i = 1; i <= pos; i++) add(f[i], i); } void query(char *S) { int loc = 1, u = 0; for (int i = 0, len = strlen(S); i < len; i++) { if (S[i] == 'P') { while (loc <= m && que[loc].y == val[u]) ans[que[loc].id] = BT.count(dfn[mp[que[loc].x]]+size[mp[que[loc].x]]-1)-BT.count(dfn[mp[que[loc].x]]-1), ++loc; }else if (S[i] == 'B') BT.add(dfn[u], -1), u = pre[u]; else u = ch[u][S[i]-'a'], BT.add(dfn[u], 1); } }}T;void dfs(int o) { size[o] = 1, dfn[o] = ++idx; for (int i = path[o]; i; i = edge[i].next) { dfs(edge[i].to); size[o] += size[edge[i].to]; }}void work() { scanf("%s", ch); T.build(ch); T.get_fail(); dfs(0); read(m); for (int i = 1; i <= m; i++) read(que[i].x), read(que[i].y), que[i].id = i; sort(que+1, que+1+m); T.query(ch); for (int i = 1; i <= m; i++) writeln(ans[i]);}int main() { work(); return 0;}

转载于:https://www.cnblogs.com/NaVi-Awson/p/8597314.html

你可能感兴趣的文章
BZOJ1045 HAOI2008 糖果传递
查看>>
发送请求时params和data的区别
查看>>
JavaScript 克隆数组
查看>>
eggs
查看>>
一步步学习微软InfoPath2010和SP2010--第七章节--从SP列表和业务数据连接接收数据(4)--外部项目选取器和业务数据连接...
查看>>
如何增强你的SharePoint 团队网站首页
查看>>
FZU 1914 Funny Positive Sequence(线性算法)
查看>>
oracle 报错ORA-12514: TNS:listener does not currently know of service requested in connec
查看>>
基于grunt构建的前端集成开发环境
查看>>
MySQL服务读取参数文件my.cnf的规律研究探索
查看>>
java string(转)
查看>>
__all__有趣的属性
查看>>
BZOJ 5180 [Baltic2016]Cities(斯坦纳树)
查看>>
写博客
查看>>
利用循环播放dataurl的视频来防止锁屏:NoSleep.js
查看>>
python3 生成器与迭代器
查看>>
java编写提升性能的代码
查看>>
ios封装静态库技巧两则
查看>>
Educational Codeforces Round 46 (Rated for Div. 2)
查看>>
Abstract Factory Pattern
查看>>