https://www.luogu.com.cn/problem/P5840
题意:中文题,给你n个串,然后m次操作,两种操作。
1操作,集合T加入一个串。2操作,询问集合T中出现上面的n个串的第i个几次。
首先听说解法挺多的,如果有幸学会了,后来补上吧。
做法:这里用AC自动机做吧,首先对n个串建立AC自动机,建立fail树,然后每一次往T集合中加入一个字符串,就让他到AC自动机中跑,跑到的点对应到fail树上点到根上的串表示都出现了,但不过一次加入中只每个点最多只能加1,因此需要去重,同时对于同一条链上点,需要利用DFS序加LCA处理一下。统计的时候就用树状数组吧。
下面这份代码可能写丑了,不开O2勉强卡过去。
#include "bits/stdc++.h"
using namespace std;
inline int read() {
int x = 0;
bool f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = 0;
for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
if (f) return x;
return 0 - x;
}
typedef long long ll;
const int maxn = 2000000 + 10;
const ll mod = 1000000000 + 7;
#define lowbit(x) x&-x
int nxt[maxn][26], fail[maxn], endd[maxn], tot = 0;
int modify(char *s) {
int len = strlen(s);
int now = 0;
for (int i = 0; i < len; i++) {
int id = s[i] - 'a';
if (nxt[now][id] == 0) nxt[now][id] = ++tot;
now = nxt[now][id];
}
// endd[now]++;
return now;
}
void build() {
queue<int> qu;
for (int i = 0; i < 26; i++) {
if (nxt[0][i] != 0) qu.push(nxt[0][i]);
}
while (!qu.empty()) {
int u = qu.front();
qu.pop();
for (int i = 0; i < 26; i++) {
if (nxt[u][i] != 0) fail[nxt[u][i]] = nxt[fail[u]][i], qu.push(nxt[u][i]);
else nxt[u][i] = nxt[fail[u]][i];
}
}
}
struct node {
int v, nxt;
} ed[maxn];
int head[maxn], gcnt;
void add_ed(int u, int v) {
++gcnt;
ed[gcnt].v = v;
ed[gcnt].nxt = head[u];
head[u] = gcnt;
}
int cnt, in[maxn], ou[maxn], dep[maxn], p[maxn][22], fa[maxn];
int n, m, dis[maxn], id[maxn], point[maxn];
void dfs(int u, int f, int deep) {
fa[u] = f, dep[u] = deep;
in[u] = ++cnt, point[cnt] = u;
for (int i = head[u]; i; i = ed[i].nxt) {
int v = ed[i].v;
dfs(v, u, deep + 1);
}
ou[u] = cnt;
}
void init_lca() {
memset(p, -1, sizeof(p));
for (int i = 1; i <= tot; i++) p[i][0] = fa[i];
for (int j = 1; (1 << j) <= tot; j++)
for (int i = 1; i <= tot; i++)
if (p[i][j - 1] != -1)
p[i][j] = p[p[i][j - 1]][j - 1];
}
int LCA(int x, int y) {
if (dep[x] < dep[y]) swap(x, y);
int lg = 21;
for (int i = lg; i >= 0; i--)
if (dep[x] - (1 << i) >= dep[y])
x = p[x][i];
if (x == y) return x;
for (int i = lg; i >= 0; i--)
if (p[x][i] != -1 && p[x][i] != p[y][i])
x = p[x][i], y = p[y][i];
return fa[x];
}
int seg[maxn];
char s[maxn];
int low[maxn];
inline void add(int x, int val) {
for (; x < tot + 10; x += lowbit(x)) low[x] += val;
}
inline int query(int x) {
int ret = 0;
for (; x; x -= lowbit(x)) ret += low[x];
return ret;
}
int main() {
n = read();
for (int i = 1; i <= n; i++) {
scanf("%s", s);
id[i] = modify(s);
}
build();
for (int i = 1; i <= tot; i++) {
add_ed(fail[i], i);
}
dfs(0, -1, 0);
init_lca();
m = read();
int x, y;
while (m--) {
x = read();
if (x == 1) {
scanf("%s", s);
int root = 0, count = 0, len = strlen(s);
for (int i = 0; i < len; i++) {
root = nxt[root][s[i] - 'a'];
seg[count++] = in[root];
}
sort(seg, seg + count);
add(seg[0], 1);
for (int i = 1; i < count; i++) {
if (seg[i] != seg[i - 1]) {
add(seg[i], 1);
add(in[LCA(point[seg[i]], point[seg[i - 1]])], -1);
}
}
} else {
y = read();
y = id[y];
printf("%d\n", query(ou[y]) - query(in[y] - 1));
}
}
return 0;
}