「NOI 2011」阿狸的打字机
作者:互联网
Description |
给定 n 个字符串,m 次询问第 x 个字符串在第 y 个字符串中出现了多少次。n,m≤105
Solution |
建立AC自动机和 fail 树,问题转化为:fail 树上 x 串的终止节点的子树中有多少个节点属于 y 串。
求出 fail 树的 dfs 序,将询问离线,并在 y 的终止节点处打上标记。
在AC自动机上 dfs,每到达一个点就在树状数组中将其 dfs 序 +1,离开时再 −1,这样树状数组中存的就是当前点到 0 号点的链,若当前点有标记,则在树状数组上查询 x 的子树的和即可。
#include <queue>
#include <cstdio>
#include <cstring>
const int N = 100002;
struct List {
struct Edge {
int v, nxt;
} e[N];
int head[N], tot;
void adde(int u, int v) {
e[++tot].nxt = head[u], head[u] = tot, e[tot].v = v;
}
} a, b;
int siz[N], dfn[N], cnt, ch[N][26], tr[N][26];
int fa[N], fail[N], ed[N], ans[N], sum[N], sz;
char s[N];
int read() {
int x = 0; char c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9')
x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
return x;
}
void update(int x, int y) {
while (x <= sz + 1)
sum[x] += y, x += x & (-x);
}
int query(int x) {
int res = 0;
while (x)
res += sum[x], x -= x & (-x);
return res;
}
void build() {
int n = strlen(s), x = 0;
for (int i = 0; i < n; ++i) {
if (s[i] == 'P') ed[++ed[0]] = x;
else if (s[i] == 'B') x = fa[x];
else {
int c = s[i] - 'a';
if (!ch[x][c])
tr[x][c] = ch[x][c] = ++sz, fa[ch[x][c]] = x;
x = ch[x][c];
}
}
for (int i = 0; i <= sz; ++i) a.head[i] = b.head[i] = -1;
std::queue<int> q;
for (int i = 0; i < 26; ++i)
if (ch[0][i]) a.adde(0, ch[0][i]), q.push(ch[0][i]);
while (!q.empty()) {
int x = q.front();
q.pop();
for (int i = 0; i < 26; ++i) {
if (!ch[x][i])
ch[x][i] = ch[fail[x]][i];
else {
fail[ch[x][i]] = ch[fail[x]][i];
a.adde(fail[ch[x][i]], ch[x][i]), q.push(ch[x][i]);
}
}
}
}
void dfs1(int u) {
siz[u] = 1, dfn[u] = ++cnt;
for (int i = a.head[u]; ~i; i = a.e[i].nxt)
dfs1(a.e[i].v), siz[u] += siz[a.e[i].v];
}
void dfs2(int u) {
update(dfn[u], 1);
for (int i = b.head[u]; ~i; i = b.e[i].nxt)
ans[i] = query(dfn[b.e[i].v] + siz[b.e[i].v] - 1) - query(dfn[b.e[i].v] - 1);
for (int i = 0; i < 26; ++i)
if (tr[u][i]) dfs2(tr[u][i]);
update(dfn[u], -1);
}
int main() {
scanf("%s", s), build(), dfs1(0);
int m = read();
for (int i = 1, x, y; i <= m; ++i)
x = read(), y = read(), b.adde(ed[y], ed[x]);
dfs2(0);
for (int i = 1; i <= m; ++i) printf("%d\n", ans[i]);
return 0;
}
标签:26,ch,NOI,阿狸,int,++,dfn,fail,2011 来源: https://blog.csdn.net/Milkyyyyy/article/details/89522588