Description
阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。打字机上只有28个按键,分别印有26个小写英文字母和’B’、’P’两个字母。
经阿狸研究发现,这个打字机是这样工作的:
- 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后)。
- 按一下印有’B’的按键,打字机凹槽中最后一个字母会消失。
- 按一下印有’P’的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失。
例如,阿狸输入aPaPBbP,纸上被打印的字符如下:
a
aa
ab
我们把纸上打印出来的字符串从
开始顺序编号,一直到
。打字机有一个非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数
(其中
),打字机会显示第
个打印的字符串在第
个打印的字符串中出现了多少次。
阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助他么?
Solution
首先对于题中所给的三个操作,对应在Trie上分别是:
- 小写字母 -> 走到当前节点的该字母的子节点(如果没有就新建一个)。
- P -> 打一个结束标记
- B -> 返回父节点
我们先根据上面的规则建出题目所给串对应的AC自动机。
AC自动机的
fail
树的性质:
如果自动机中的两个串 , 满足 在 中出现了 次,那么 等于 串结束点在Fail
树上的子树中有多少个节点属于串 。
有了这个性质,我们可以先求出Fail
树的dfn
。
对于每次询问,按
排序,在输入的串上面走一遍,每走到一个点就将其dfn
插入树状数组,每离开一个点就将其dfn
在树状数组上删掉。如果走到了询问的
,我们查询树状数组中有多少个点再
对应节点的子树的dfn
范围内即可。
Code
/************************************************
* Au: Hany01
* Date: May 5th, 2018
* Prob: [BZOJ2434][NOI2011] 阿狸的打字机
* Email: [email protected]
************************************************/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
#define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)
#define rep(i, j) for (register int i = 0, i##_end_ = (j); i < i##_end_; ++ i)
#define For(i, j, k) for (register int i = (j), i##_end_ = (k); i <= i##_end_; ++ i)
#define Fordown(i, j, k) for (register int i = (j), i##_end_ = (k); i >= i##_end_; -- i)
#define Set(a, b) memset(a, b, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define x first
#define y second
#define pb(a) push_back(a)
#define mp(a, b) make_pair(a, b)
#define ALL(a) (a).begin(), (a).end()
#define SZ(a) ((int)(a).size())
#define INF (0x3f3f3f3f)
#define INF1 (2139062143)
#define Mod (1000000007)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define y1 wozenmezhemecaia
template <typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
template <typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
inline int read()
{
register int _, __; register char c_;
for (_ = 0, __ = 1, c_ = getchar(); c_ < '0' || c_ > '9'; c_ = getchar()) if (c_ == '-') __ = -1;
for ( ; c_ >= '0' && c_ <= '9'; c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ ^ 48);
return _ * __;
}
////////////////////////Statement////////////////////////////
const int maxn = 100005;
int n, Ans[maxn], dfn[maxn], efn[maxn], tot, cnt, now, len, beg[maxn], nex[maxn], v[maxn], e, clk, pos[maxn];
char s[maxn];
//////////////////Aho-Corasick Automaton/////////////////////
struct Node
{
int ch[26], fa, fail;
}t[maxn];
inline void buildTrie()
{
static int u = 0;
rep(i, len)
if (s[i] == 'B') u = t[u].fa;
else if (s[i] != 'P') {
register int c = s[i] - 97;
if (!t[u].ch[c]) t[u].ch[c] = ++ tot, t[tot].fa = u;
u = t[u].ch[c];
} else pos[++ cnt] = u;
cnt = 0;
}
inline void getFail()
{
static queue<int> q;
rep(i, 26) if (t[0].ch[i]) q.push(t[0].ch[i]);
while (!q.empty()) {
register int u = q.front(), v, w; q.pop();
rep(i, 26) if (v = t[u].ch[i]) {
w = t[u].fail;
while (w && !t[w].ch[i]) w = t[w].fail;
t[v].fail = t[w].ch[i], q.push(v);
}
}
}
/////////////////////Build Tree//////////////////////////////
inline void add(int uu, int vv) { v[++ e] = vv, nex[e] = beg[uu], beg[uu] = e; }
void getdfn(int u)
{
dfn[u] = ++ clk;
for (register int i = beg[u]; i; i = nex[i]) getdfn(v[i]);
efn[u] = clk;
}
////////////////////Answer Questions/////////////////////////
struct Question
{
int p, s, id;
bool operator < (const Question& A) const { return s < A.s; };
}Q[maxn];
struct FenwickTree
{
int c[maxn];
#define lb(x) ((x) & -(x))
inline void update(int x, int dt) {
for ( ; x <= clk; x += lb(x)) c[x] += dt;
}
inline int query(int x) {
register int Ans = 0;
for ( ; x; x -= lb(x)) Ans += c[x];
return Ans;
}
inline int query(int l, int r) { return query(r) - query(l - 1); }
}FT;
inline void Solve()
{
static int u = 0;
rep(i, len) {
if (s[i] == 'B') FT.update(dfn[u], -1), u = t[u].fa;
else if (s[i] == 'P') {
++ cnt;
while (cnt == Q[now].s)
Ans[Q[now].id] = FT.query(dfn[pos[Q[now].p]], efn[pos[Q[now].p]]), ++ now;
} else u = t[u].ch[s[i] - 97], FT.update(dfn[u], 1);
}
}
//////////////////////Main Function//////////////////////////
int main()
{
#ifdef hany01
File("bzoj2434");
#endif
scanf("%s", s), len = strlen(s);
buildTrie(), getFail();
For(i, 1, tot) add(t[i].fail, i);
getdfn(0);
n = read();
For(i, 1, n) Q[i].p = read(), Q[i].s = read(), Q[i].id = i;
sort(Q + 1, Q + 1 + n);
now = 1, Solve();
For(i, 1, n) printf("%d\n", Ans[i]);
return 0;
}
//岭上逢久别者又别
//唐代 权德舆
//十年曾一别,征路此相逢。
//马首向何处?夕阳千万峰。