SCOI2012 喵星球上的点名
题意就不说了, 反正是中文;
正解应该是后缀数组, 但是AC自动机可以强行过, 只是比较慢;
对于询问串建AC自动机, 然后暴力把每个喵星人暴力在树上跑, 然后。。。就没有然后了。
#include <bits/stdc++.h>
const int mx_n = 2e4 + 10;
const int mx_m = 5e4 + 10;
const int mx_node = 1e5 + 10;
#define pb push_back
#define rep(i, s, t) for(register int i = s; i <= t; ++i)
using namespace std;
template <class T>
T read(T x = 0) {
char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9')
x = x*10 + c-'0', c = getchar();
return x;
}
vector<int> G[mx_n];
int n, m, Ans[mx_m], Cat[mx_n];
namespace aho_corasick {
queue<int> Q;
int tot, fail[mx_node];
vector<int> val[mx_node];
map<int, int> ch[mx_node];
void Bfs_fail() {
Q.push(0);
while(!Q.empty()) {
int u = Q.front(); Q.pop();
for(map<int, int>::iterator it = ch[u].begin(); it != ch[u].end(); ++it) {
int x = it -> first, y = it -> second;
if(u) {
int t = fail[u];
for(; t && !ch[t][x]; t = fail[t]);
fail[y] = ch[t][x];
}Q.push(y);
}
}
}
}using namespace aho_corasick;
int s[mx_n], vis[mx_m];
void Query(int x) {
int u = 0, top = 0;
rep(i, 0, (int) G[x].size()-1) {
int id = G[x][i];
for(; u && !ch[u][id]; u = fail[u]);
for(int v = (u=ch[u][id]); v; v = fail[v])
rep(j, 0, (int)val[v].size()-1) if(!vis[val[v][j]]) {
++Cat[x], ++Ans[val[v][j]], vis[s[++top]=val[v][j]] = 1;
}
}rep(i, 1, top) vis[s[i]] = 0;
}
void input() {
n = read<int>(), m = read<int>();
rep(i, 1, n) rep(Case, 0, 1) {
int len = read<int>();
while(len--) G[i].pb(read<int>());
G[i].pb(10002);
}rep(i, 1, m) {
int u = 0;
int len = read<int>();
while(len--) {
int x = read<int>();
if(!ch[u][x]) ch[u][x] = ++tot;
u = ch[u][x];
}val[u].pb(i);
}Bfs_fail();
}
int main() {
input();
rep(i, 1, n) Query(i);
rep(i, 1, m) printf("%d\n", Ans[i]);
rep(i, 1, n)
printf("%d%c", Cat[i], i ^ n? ' ': '\n');
return 0;
}