BZOJ 2754 [SCOI2012]喵星球上的点名 (AC自动机、树状数组)
吐槽: 为啥很多人用AC自动机暴力跳都过了?复杂度真的对么?
做法一: AC自动机+树状数组
姓名的问题,中间加个特殊字符连起来即可。
肯定是对点名串建AC自动机(map存儿子),然后第一问就相当于问每个姓名串(以下称作“关键路径”)经过了多少个点名串(以下称做“关键点”)在fail树中的子树中的至少一点,第二问就相当于问你每条关键路径被多少个关键点经过了在fail树的子树中至少一个点。
所以对于每个关键路径在AC自动机上跑,每跑到一个点把它到根的路径上打上标记(注意每个姓名串要有不同的标记),最后统计标记个数即可。
然后如果暴力跳去更新可过,我不知道复杂度对不对,感觉是错的。(也许是\(O(n\sqrt n)\)?)
脑子里第一思路是用bitset, 可以在暴力的复杂度基础上除以\(\omega\), 没试过
第二思路是线段树/启发式合并,没仔细想
最后看了一波题解: 我们的目标就是让同一关键路径上的点只被加一次,这样就可以变或为加,不需要状压bitset了。
然后一种好办法是像虚树那样按DFS序排序,相邻两个求出LCA,在LCA到根的路径上-1. 差分树状数组维护即可。
时间复杂度\(O(n\log n)\)
易错点: 注意AC自动机不补成Trie图,绝对不能再fail[son[u][i]]=son[fail[u]][i]了!(一晚上的惨痛教训……) 即使是写板子也要经过脑子!!!!!!!
听说也可以SA+主席树?并不会233
**UPD: **BZOJ2780是本题的一部分,求每个点名串是多少姓名串的子串,SA的做法是把所有点名串连成一起然后求SA,转化成了求区间内有多少种不同的颜色。也有更简单的SAM做法,不用任何数据结构\(O(n)\), 对所有姓名串建广义SAM,再求出来每个点有多少个姓名串经过,然后拿点名串在上面跑,跑到结尾节点输出个数即可。
代码
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
const int N = 5e4;
const int S = 5e4+1;
const int SIZ = 1e5;
const int LGSIZ = 16;
struct Edge
{
int v,nxt;
} e[(SIZ<<1)+3];
int fe[SIZ+3];
vector<int> a[N+3];
vector<int> b[N+3];
vector<int> ky;
map<int,int> son[SIZ+3];
int fail[SIZ+3];
int id[N+3];
int tr[SIZ+3];
int que[SIZ+3];
int ansa[N+3],ansb[N+3];
int dfn[SIZ+3];
int fa[SIZ+3][LGSIZ+3];
int sz[SIZ+3];
int dep[SIZ+3];
int num[SIZ+3];
int n,m,siz,en,cnt;
void addval(int lrb,int val)
{
while(lrb<=cnt)
{
tr[lrb] += val;
lrb += (lrb&(-lrb));
}
}
int querysum(int rb)
{
int ret = 0;
while(rb>0)
{
ret += tr[rb];
rb -= (rb&(-rb));
}
return ret;
}
int insertstr(vector<int> str)
{
int u = 0;
for(int i=0; i<str.size(); i++)
{
if(son[u].count(str[i])==0) {siz++; son[u][str[i]] = siz;}
u = son[u][str[i]];
}
num[u]++;
return u;
}
void buildACA()
{
int head = 1,tail = 0;
for(map<int,int>::iterator iter=son[0].begin(); iter!=son[0].end(); iter++)
{
int u = (iter->second);
tail++; que[tail] = u; fail[u] = 0;
}
while(head<=tail)
{
int u = que[head]; head++;
for(map<int,int>::iterator iter=son[u].begin(); iter!=son[u].end(); iter++)
{
int v = (iter->second),i = (iter->first);
if(v)
{
int uu = fail[u];
while(uu && !son[uu].count(i)) {uu = fail[uu];}
fail[v] = son[uu][i];
tail++; que[tail] = v;
}
}
}
}
void addedge(int u,int v)
{
en++; e[en].v = v;
e[en].nxt = fe[u]; fe[u] = en;
}
void dfs(int u)
{
cnt++; dfn[u] = cnt;
sz[u] = 1;
for(int i=1; i<=LGSIZ; i++) fa[u][i] = fa[fa[u][i-1]][i-1];
for(int i=fe[u]; i; i=e[i].nxt)
{
if(e[i].v==fa[u][0]) continue;
fa[e[i].v][0] = u;
dep[e[i].v] = dep[u]+1;
num[e[i].v] += num[u];
dfs(e[i].v);
sz[u] += sz[e[i].v];
}
}
int LCA(int u,int v)
{
if(dep[u]<dep[v]) swap(u,v);
int dif = dep[u]-dep[v];
for(int i=LGSIZ; i>=0; i--) {if(dif&(1<<i)) {u = fa[u][i];}}
if(u==v) return u;
for(int i=LGSIZ; i>=0; i--) {if(fa[u][i]!=fa[v][i]) {u = fa[u][i]; v = fa[v][i];}}
return fa[u][0];
}
bool cmp_dfn(int x,int y) {return dfn[x]<dfn[y];}
int main()
{
scanf("%d%d",&n,&m); siz = 0;
for(int i=1; i<=n; i++)
{
int len; scanf("%d",&len); for(int j=1; j<=len; j++) {int x; scanf("%d",&x); a[i].push_back(x);}
a[i].push_back(S);
scanf("%d",&len); for(int j=1; j<=len; j++) {int x; scanf("%d",&x); a[i].push_back(x);}
}
for(int i=1; i<=m; i++)
{
int len; scanf("%d",&len); for(int j=1; j<=len; j++) {int x; scanf("%d",&x); b[i].push_back(x);}
id[i] = insertstr(b[i]);
}
buildACA();
for(int i=1; i<=siz; i++)
{
addedge(fail[i],i); addedge(i,fail[i]);
}
cnt = 0; dfs(0);
for(int i=1; i<=n; i++)
{
int u = 0; ky.push_back(u);
for(int j=0; j<a[i].size(); j++)
{
while(u && !son[u][a[i][j]]) {u = fail[u];}
u = son[u][a[i][j]]; if(u) ky.push_back(u);
}
sort(ky.begin(),ky.end(),cmp_dfn);
for(int j=0; j<ky.size(); j++)
{
if(j>0)
{
int lca = LCA(ky[j],ky[j-1]);
addval(dfn[lca],-1); ansa[i] -= num[lca];
}
addval(dfn[ky[j]],1); ansa[i] += num[ky[j]];
}
ky.clear();
}
for(int i=1; i<=m; i++)
{
ansb[i] = querysum(dfn[id[i]]+sz[id[i]]-1)-querysum(dfn[id[i]]-1);
}
for(int i=1; i<=m; i++) printf("%d\n",ansb[i]);
for(int i=1; i<=n; i++) printf("%d ",ansa[i]);
return 0;
}
BZOJ 2754 [SCOI2012]喵星球上的点名 (AC自动机、树状数组)的更多相关文章
- BZOJ 2754: [SCOI2012]喵星球上的点名 [AC自动机+map+暴力]
2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 1902 Solved: 837[Submit][St ...
- BZOJ 2754 [SCOI2012]喵星球上的点名 (AC自动机+map维护Trie树)
题目大意:略 由于字符集大,要用map维护Trie树 并不能用AC自动机的Trie图优化,不然内存会炸 所以我用AC自动机暴跳fail水过的 显然根据喵星人建AC自动机是不行的,所以要根据问题建 然而 ...
- BZOJ 2754: [SCOI2012]喵星球上的点名
2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 649 Solved: 305[Submit][Sta ...
- BZOJ 2754: [SCOI2012]喵星球上的点名 [后缀数组+暴力]
2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 1906 Solved: 839[Submit][St ...
- 【刷题】BZOJ 2754 [SCOI2012]喵星球上的点名
Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点 ...
- BZOJ2754: [SCOI2012]喵星球上的点名(AC自动机)
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2816 Solved: 1246[Submit][Status][Discuss] Descript ...
- BZOJ2754: [SCOI2012]喵星球上的点名(AC自动机/后缀自动机)
Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串 ...
- bzoj 2754 [SCOI2012]喵星球上的点名(后缀数组)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2754 [题意] 每只喵有名姓,如果被老师点到名或姓的子串都要答道,但每只喵一次点名只答 ...
- bzoj 2754: [SCOI2012]喵星球上的点名【AC自动机】
洛谷90,最后一个点死活卡不过去(也可能是我写的有问题? 比较暴力的做法,把询问带着标号建立AC自动机,用map存儿子. 然后用名字串在自动机上跑,以为是名或姓的子串就行所以把名和姓中间加个特殊字符拼 ...
随机推荐
- Batch 拷贝远程机器文件到本机指定目录下
net use * /del /yesNET USE Y: \\远程机IP\d$ 登录密码 /user:domain\登录用户 set sourcePath="Y:\DOAutomatio ...
- [转]完整教程--idea使用git进行项目管理
完整教程--idea使用git进行项目管理 第一部分: 安装 1. 下载地址: https://git-scm.com/download/win; 如果速度慢, 使用 迅雷下载; 2. 点击安装, ...
- 微信小程序的wxml文件和wxss文件在webstrom的支持
webstrom默认不支持wxml文件和wxss文件,所以要进入设置里面手动添加支持. 对wxml文件的支持: 文件 -> 设置 -> 编辑器 -> 文件类型, 然后选择XML文件, ...
- 【洛谷3224/BZOJ2733】[HNOI2012]永无乡 (Splay启发式合并)
题目: 洛谷3224 分析: 这题一看\(n\leq100000\)的范围就知道可以暴力地用\(O(nlogn)\)数据结构乱搞啊-- 每个联通块建一棵Splay树,查询就是Splay查询第k大的模板 ...
- tomcat解决 java.lang.IllegalArgumentException: Request header is too large
tomcat运行项目时,有一个请求过去后,后台报这样的错java.lang.IllegalArgumentException: Request header is too large 原因:请求头超过 ...
- Servlet到Servlet的请求转发与重定向的区别
Servlet跳转到另一个Servlet中: request.getRequestDispatcher().forward();代表默认的是post方法,即在被跳转的Servlet的doPost()方 ...
- Spring Cloud (11) Hystrix-监控聚合监控
上一篇利用Hystrix Dashboard去监控断路器的Hystrix command,当我们有很多服务的时候,就需要聚合所有服务的Hystrix Dashboard数据了,这就需要Hystrix ...
- Unity学习-元素类型(三)
在看下面操作时,先记住三句话 1.游戏对象 是由 组件 组成的:衣服 2.材质(Material):就是衣服的设计方案 3.纹理(Texture):做衣服的布料 从GameObject到Cube 第一 ...
- sublime text3配置插件
之前一直习惯用记事本写代码,懒得用IDE,虽然知道用 IDE效率高一些,不过觉得还是用记事本纯手写代码,比较容易记忆.直到昨天写代码遇到了点问题,截图给师兄看,师兄就问我是不是用记事本写代码,为什么不 ...
- Java&Xml教程(七)使用JDOM修改XML文件内容
JDOM提供了非常灵活的方式操作XML文件,使用JDOM非常简单而且代码简洁可读性强.前面我们学习了如何使用JDOM解析XML文件,本节介绍如何使用JDOM修改XML文件内容. 在这个教程中,我们准备 ...