洛谷P2336 喵星球上的点名
解: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代码
洛谷P2336 喵星球上的点名的更多相关文章
- 洛谷 P2336 [SCOI2012]喵星球上的点名 解题报告
P2336 [SCOI2012]喵星球上的点名 题目描述 a180285 幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有 \(N\) 个喵星人,每个喵星人的 ...
- 洛咕 P2336 [SCOI2012]喵星球上的点名
洛咕 P2336 [SCOI2012]喵星球上的点名 先求出SA和height,一个点名串对应的就是一段区间,还有很多个点,就转化成了 有很多个区间,很多个点集,对每个区间计算和多少个点集有交,对每个 ...
- P2336 [SCOI2012]喵星球上的点名(后缀自动机+莫队+dfs序)
P2336 [SCOI2012]喵星球上的点名 名字怎么存?显然是后缀自动机辣 询问点到多少个喵喵喵其实就是 查询后缀自动机上parent树的一个子树 于是我们考虑莫队 怎么树上莫队呢 我们用dfs序 ...
- BZOJ 2754: [SCOI2012]喵星球上的点名 [后缀数组+暴力]
2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 1906 Solved: 839[Submit][St ...
- 【BZOJ2754】[SCOI2012]喵星球上的点名
[BZOJ2754][SCOI2012]喵星球上的点名 题面 bzoj 洛谷 题解 这题有各种神仙做法啊,什么暴力\(AC\)自动机.\(SAM\)等等五花八门 我这个蒟蒻在这里提供一种复杂度正确且常 ...
- BZOJ_2754__[SCOI2012]_喵星球上的点名_(暴力+后缀数组)
描述 http://www.lydsy.com/JudgeOnline/problem.php?id=2754 给出n个姓名串和m个点名串.求每个点名串在多少人的姓名中出现过(在名中出现或在姓中出现, ...
- BZOJ 2754: [SCOI2012]喵星球上的点名
2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 649 Solved: 305[Submit][Sta ...
- BZOJ2754: [SCOI2012]喵星球上的点名
2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 680 Solved: 314[Submit][Sta ...
- BZOJ 2754: [SCOI2012]喵星球上的点名 [AC自动机+map+暴力]
2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 1902 Solved: 837[Submit][St ...
随机推荐
- v-router几种定义方式
第一种 const router = new VueRouter({ routes: [{ path: '/newSongs', component: require('../views/NewSon ...
- flutter 动画双指放大图片
class GridAnimation extends StatefulWidget { @override State<StatefulWidget> createState() { r ...
- 字符串正则替换replace第二个参数是函数
zepto中 //将字符串转成驼峰式的格式 camelize = function (str) { return str.replace(/-+(.)?/g, function (match, chr ...
- php-memcached详解
一.memcached 简介 在很多场合,我们都会听到 memcached 这个名字,但很多同学只是听过,并没有用过或实际了解过,只知道它是一个很不错的东东.这里简单介绍一下,memcached 是高 ...
- Saltstack 安装与常用模块
一.介绍 saltstack是基于C/S服务模式,在该架构中,服务器端叫做Master,客户端叫做Minion.传统的C/S模式我们这样理解,客户端发送请求给服务器端,服务器端接受到来自客户端的请求并 ...
- flask保存 文件到本地
本篇队长介绍一下如何 把前端上传的文件保存 到 后端flask项目目录 首先讲一下上传.保存文件的思路: 第一步:前端通过post请求方式提交上传的文件 <input id="file ...
- java 处理上传exl数据 并导入数据库
思路:处理上传exl表格,并读取文件,数据,讲数据放去集合,循环插入数据库. 重点,读取文件时需要读数据,格式和数据是否正确,(因为只是把整条路打通,所以这块没有细弄): 项目使用ssm框架, str ...
- eclipse 等号左边代码补全
1: 2. 3.完成 “ctrl + shift + l” 代码补全成功
- spring 自己创建配置类
- AMD三代锐龙箭在弦上:如此家族堪称豪华
AMD将于今年年中正式推出第三代Ryzen锐龙处理器,即不集成显示芯片的纯CPU产品,外界猜测可能的时间点会是5月底的台北电脑展. 虽说依然采用AM4接口,也就是X370/470老主板可无压力兼容,但 ...