解:SAM + 线段树合并 + DFS序。

姓和名之间插入特殊字符,转化为下题:

给定串集合S,T,问S中每个串包含了T中的几个串?T中每个串被多少个S中的串包含?

解:对S建广义SAM,并线段树合并维护每个节点有多少串。

T中每个串在S的sam上跑,如果没能跑完就被包含0次。否则答案就是到达的节点上的串数。第二问解决。

标记T中每个串最后到达的节点。S中每个串跑S的sam会得到若干个点。统计这些点到根路径的并集上的标记个数即可。

按DFS序排序,加上每个节点到根路径的贡献,减去相邻节点lca到根路径的贡献。第一问解决。

 #include <bits/stdc++.h>

 const int N = , M = ;

 struct Edge {
int nex, v;
}edge[N]; int tp; std::map<int, int> tr[N];
int fail[N], len[N], tot = , e[N], n, m, siz[N], ed[N],
stk[N], top, num2, pos2[N], ST[N << ][], pw[N << ], d[N];
int ls[M], rs[M], num, sum[M], rt[N];
std::vector<int> str[N]; inline void add(int x, int y) {
tp++;
edge[tp].v = y;
edge[tp].nex = e[x];
e[x] = tp;
return;
} inline bool cmp(const int &a, const int &b) {
return pos2[a] < pos2[b];
} void insert(int p, int l, int r, int &o) {
if(!o) o = ++num;
if(l == r) {
sum[o] = ;
return;
}
int mid = (l + r) >> ;
if(p <= mid) insert(p, l, mid, ls[o]);
else insert(p, mid + , r, rs[o]);
sum[o] = sum[ls[o]] + sum[rs[o]];
return;
} int merge(int x, int y) {
if(!x || !y) return x | y;
int o = ++num;
ls[o] = merge(ls[x], ls[y]);
rs[o] = merge(rs[x], rs[y]);
if(!ls[o] && !rs[o]) sum[o] = ;
else sum[o] = sum[ls[o]] + sum[rs[o]];
return o;
} int ask(int L, int R, int l, int r, int o) {
if(!o) return ;
if(L <= l && r <= R) return sum[o];
int mid = (l + r) >> , ans = ;
if(L <= mid) ans += ask(L, R, l, mid, ls[o]);
if(mid < R) ans += ask(L, R, mid + , r, rs[o]);
return ans;
} void DFS_1(int x) {
pos2[x] = ++num2;
ST[num2][] = x;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
d[y] = d[x] + ;
DFS_1(y);
ST[++num2][] = x;
rt[x] = merge(rt[x], rt[y]);
}
return;
} inline void prework() {
for(int i = ; i <= num2; i++) pw[i] = pw[i >> ] + ;
for(int j = ; j <= pw[num2]; j++) {
for(int i = ; i + (j << ) - <= num2; i++) {
if(d[ST[i][j - ]] < d[ST[i + ( << (j - ))][j - ]])
ST[i][j] = ST[i][j - ];
else
ST[i][j] = ST[i + ( << (j - ))][j - ];
}
}
return;
} inline int lca(int x, int y) {
x = pos2[x];
y = pos2[y];
if(x > y) std::swap(x, y);
int t = pw[y - x + ];
if(d[ST[x][t]] < d[ST[y - ( << t) + ][t]])
return ST[x][t];
else
return ST[y - ( << t) + ][t];
} void DFS_2(int x) {
siz[x] += ed[x];
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
siz[y] = siz[x];
DFS_2(y);
}
return;
} inline int split(int p, int f) {
int Q = tr[p][f], nQ = ++tot;
len[nQ] = len[p] + ;
fail[nQ] = fail[Q];
fail[Q] = nQ;
//memcpy(tr[nQ], tr[Q], sizeof(tr[Q]));
tr[nQ] = tr[Q];
while(tr[p][f] == Q) {
tr[p][f] = nQ;
p = fail[p];
}
return nQ;
} inline int insert(int p, int f, int id) {
int np;
if(tr[p].count(f)) {
int Q = tr[p][f];
if(len[Q] == len[p] + ) {
np = Q;
}
else {
np = split(p, f);
}
insert(id, , n, rt[np]);
return np;
}
np = ++tot;
len[np] = len[p] + ;
while(p && !tr[p].count(f)) {
tr[p][f] = np;
p = fail[p];
}
if(!p) {
fail[np] = ;
}
else {
int Q = tr[p][f];
if(len[Q] == len[p] + ) {
fail[np] = Q;
}
else {
fail[np] = split(p, f);
}
}
insert(id, , n, rt[np]);
return np;
} void out(int l, int r, int o) {
if(!o) return;
if(l == r) {
printf("%d ", r);
return;
}
int mid = (l + r) >> ;
out(l, mid, ls[o]);
out(mid + , r, rs[o]);
return;
} inline void clear() {
for(int i = ; i <= tot; i++) {
e[i] = len[i] = fail[i] = rt[i] = ;
tr[i].clear();
}
for(int i = ; i <= num; i++) {
ls[i] = rs[i] = sum[i] = ;
}
tp = num = ;
tot = ;
return;
} int main() {
scanf("%d%d", &n, &m);
for(int i = ; i <= n; i++) {
int k, x, p = ;
scanf("%d", &k);
for(int j = ; j <= k; j++) {
scanf("%d", &x);
str[i].push_back(x);
p = insert(p, x, i);
}
str[i].push_back(-);
p = insert(p, -, i);
scanf("%d", &k);
for(int j = ; j <= k; j++) {
scanf("%d", &x);
str[i].push_back(x);
p = insert(p, x, i);
}
}
/// build
for(int i = ; i <= tot; i++) {
//printf("add %d %d \n", fail[i], i);
add(fail[i], i);
}
DFS_1(); for(int i = ; i <= m; i++) {
int k, x, p = , fd = , ans = ;
scanf("%d", &k);
for(int j = ; j <= k; j++) {
scanf("%d", &x);
if(!tr[p].count(x)) fd = ;
else p = tr[p][x];
}
if(!fd) {
ans = sum[rt[p]];
ed[p]++;
}
printf("%d\n", ans);
} DFS_2();
prework(); for(int i = ; i <= n; i++) {
int p = ; top = ;
for(int j = ; j < (int)str[i].size(); j++) {
int x = str[i][j];
p = tr[p][x];
stk[++top] = p;
}
std::sort(stk + , stk + top + ,cmp);
top = std::unique(stk + , stk + top + ) - stk - ;
int ans = ;
for(int j = ; j <= top; j++) {
ans += siz[stk[j]];
if(j < top) ans -= siz[lca(stk[j], stk[j + ])];
}
printf("%d ", ans);
} return ;
}

AC代码

AC自动机解法

洛谷P2336 喵星球上的点名的更多相关文章

  1. 洛谷 P2336 [SCOI2012]喵星球上的点名 解题报告

    P2336 [SCOI2012]喵星球上的点名 题目描述 a180285 幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有 \(N\) 个喵星人,每个喵星人的 ...

  2. 洛咕 P2336 [SCOI2012]喵星球上的点名

    洛咕 P2336 [SCOI2012]喵星球上的点名 先求出SA和height,一个点名串对应的就是一段区间,还有很多个点,就转化成了 有很多个区间,很多个点集,对每个区间计算和多少个点集有交,对每个 ...

  3. P2336 [SCOI2012]喵星球上的点名(后缀自动机+莫队+dfs序)

    P2336 [SCOI2012]喵星球上的点名 名字怎么存?显然是后缀自动机辣 询问点到多少个喵喵喵其实就是 查询后缀自动机上parent树的一个子树 于是我们考虑莫队 怎么树上莫队呢 我们用dfs序 ...

  4. BZOJ 2754: [SCOI2012]喵星球上的点名 [后缀数组+暴力]

    2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1906  Solved: 839[Submit][St ...

  5. 【BZOJ2754】[SCOI2012]喵星球上的点名

    [BZOJ2754][SCOI2012]喵星球上的点名 题面 bzoj 洛谷 题解 这题有各种神仙做法啊,什么暴力\(AC\)自动机.\(SAM\)等等五花八门 我这个蒟蒻在这里提供一种复杂度正确且常 ...

  6. BZOJ_2754__[SCOI2012]_喵星球上的点名_(暴力+后缀数组)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=2754 给出n个姓名串和m个点名串.求每个点名串在多少人的姓名中出现过(在名中出现或在姓中出现, ...

  7. BZOJ 2754: [SCOI2012]喵星球上的点名

    2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 649  Solved: 305[Submit][Sta ...

  8. BZOJ2754: [SCOI2012]喵星球上的点名

    2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 680  Solved: 314[Submit][Sta ...

  9. BZOJ 2754: [SCOI2012]喵星球上的点名 [AC自动机+map+暴力]

    2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1902  Solved: 837[Submit][St ...

随机推荐

  1. API知识点总结

    一.开发api接口开放给其他人调用的api接口(短信接口,支付宝api) 二.api安全弱点数据窃取(解决加密),数据篡改(解决MD5),数据泄露(爬虫技术)(解决令牌)1.加密(HTTPS传输-收费 ...

  2. Web移动端---iPhone X适配(底部栏黑横线)

    一.相信大家有被iPhone X底部黑色横线支配的恐惧 上面我们可以看到,底部的导航栏被一条黑色横线所盖住,那么就很烦.下面我们可以开始进行适配环节 1.首先我们可以用 JS 判断手机环境是不是 iP ...

  3. Spring JDBC模版以及三种数据库连接池的使用

    jar包版本有点乱,直接忽略版本号,将就一下. 这里引了aop包是因为在spring3版本之后用模版对数据库库操作时会出现问题,但是不会报错,也没有提示. 所以这里直接引入,以及之后会用到的DBCP与 ...

  4. Linux在shell中进入python敲方向键出现「^[[C^[[D」的解决办法

    安装yum -y install readline-devel,然后在重新编译python

  5. 使用php导出excel并使用excel的求和统计函数对excel进行汇总

    1. 使用excel的统计函数对excel进行多条件汇总求和: =SUMIFS($D$:$D$, $A$:$A$, :$B$, :$C$, "三级片") 例如: =SUMIFS(求 ...

  6. Maven最佳实战

    Maven中内置的隐藏变量: http://www.cnblogs.com/quanyongan/category/471332.html Maven提供了三个隐式的变量可以用来访问环境变量,POM信 ...

  7. faster rcnn训练详解

    http://blog.csdn.net/zy1034092330/article/details/62044941 py-faster-rcnn训练自己的数据:流程很详细并附代码 https://h ...

  8. mysql-语法大全

    DDL语句 库 创建 create database 库名 charset utf8; 删除 drop database 库名; 修改 alter database 库名 charset latin; ...

  9. Java虚拟机构建对象过程小记

    Java对象的内存分布 Java对象的构建 Java程序中,新建对象,除了常见的new语句之外,还可以通过反射机制.Object.clone方法.反序列化以及Unsafe.allocateInstan ...

  10. 学习Android过程中遇到的问题及解决方法——网络请求

    在学习Android的网络连接时遇到崩溃或异常(出现的问题就这两个,但是不稳定)的问题,先上代码,看看哪里错了(答案在文末) activity_main.xml: <?xml version=& ...