BZOJ 3881 [COCI2015]Divljak (Trie图+Fail树+树链的并+树状数组维护dfs序)
题目大意:
Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的。
接下来会发生q个操作,操作有两种形式:
最先想歪了,想把$T$里的串建自动机,最后失败了..
正解是对Alice的字符串建AC自动机,再建$Fail$树
那么对于操作1,每加入一个字符串,就把这个串放到AC自动机上跑
再把路径上的所有点记下来,新加入的字符串会对连接这些节点的树链上的所有点产生1点贡献
即求树链的并,用树状数组维护$dfs$序
先把这些节点按照$dfs$序排序,然后在树上打差分,树状数组维护前缀和,单点修改
每个节点都+1,$dfs$序中相邻节点的$lca$-1,最后在全局$lca$的父节点-1
询问就是子树查询
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define NN 2001000
#define MM 1510
#define ll long long
#define dd double
#define uint unsigned int
#define mod 1000000007
#define idx(X) (X-'a')
#define eps (1e-9)
using namespace std; int n,m,cte;
int head[NN];
struct Edge{int to,nxt;}edge[NN];
void ae(int u,int v){
cte++;edge[cte].nxt=head[u];
head[u]=cte,edge[cte].to=v;
}
struct BIT{
int sum[NN*],tot;
void update(int x,int w){
for(int i=x;i<=tot;i+=(i&(-i)))
sum[i]+=w;}
int query(int x){
int ans=;
for(int i=x;i>;i-=(i&(-i)))
ans+=sum[i];
return ans;}
}b;
namespace AC{
int ch[NN][],fail[NN],tot,ed[NN],dep[NN];
void Build_Trie(char *str,int len,int id)
{
int x=;
for(int i=;i<=len;i++){
if(!ch[x][idx(str[i])])
ch[x][idx(str[i])]=++tot,
dep[tot]=dep[x]+;
x=ch[x][idx(str[i])];
}ed[id]=x;
}
void Build_Fail()
{
queue<int>q;
for(int i=;i<;i++)
if(ch[][i]) q.push(ch[][i]);
while(!q.empty())
{
int x=q.front();q.pop();
ae(fail[x],x);
for(int i=;i<;i++)
{
if(ch[x][i]){
fail[ch[x][i]]=ch[fail[x]][i];
q.push(ch[x][i]);
}else{
ch[x][i]=ch[fail[x]][i];
}
}
}
}
};
char str[NN];
namespace T{
int son[NN],sz[NN],tp[NN],fa[NN],dep[NN];
int st[NN],ed[NN],tot;
void dfs1(int u,int dad)
{
for(int j=head[u];j;j=edge[j].nxt){
int v=edge[j].to;
if(v==dad) continue;
fa[v]=u;dep[v]=dep[u]+;
dfs1(v,u);
son[u]=sz[v]>sz[son[u]]?v:son[u];
}sz[u]++;
}
void dfs2(int u)
{
st[u]=++tot;
if(son[u]) tp[son[u]]=tp[u],dfs2(son[u]);
for(int j=head[u];j;j=edge[j].nxt){
int v=edge[j].to;
if(v==fa[u]||v==son[u]) continue;
tp[v]=v,dfs2(v);
}ed[u]=++tot;
}
int LCA(int x,int y)
{
while(tp[x]!=tp[y]){
if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
x=fa[tp[x]];
}return dep[x]<dep[y]?x:y;
}
int stk[NN],num;
int cmp(int x,int y){return st[x]<st[y];}
void update(char *str,int len)
{
int x=,y,ff,v;
for(int i=;i<=len;i++){
v=AC::ch[x][idx(str[i])];
if((!v)) break;
x=v;stk[++num]=x;
}
sort(stk+,stk+num+,cmp);
x=stk[];
if(num==){
b.update(st[x],);
b.update(st[fa[x]],-);
}else{
b.update(st[x],);
for(int i=;i<=num;i++)
{
y=stk[i];ff=LCA(x,y);
b.update(st[y],);
b.update(st[ff],-);
x=stk[i];
}ff=LCA(stk[],stk[num]);
b.update(st[fa[ff]],-);
}
while(num) stk[num--]=;
}
int query(int x)
{return b.query(ed[x])-b.query(st[x]-);}
void solve()
{
dep[]=;dfs1(,-);
tp[]=;dfs2();
scanf("%d",&m);
int fl,x;
b.tot=tot;
for(int i=;i<=m;i++)
{
scanf("%d",&fl);
if(fl==){
scanf("%s",str+);
int len=strlen(str+);
update(str,len);
}else{
scanf("%d",&x);
printf("%d\n",query(AC::ed[x]));
}
}
}
}; int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%s",str+);
int len=strlen(str+);
AC::Build_Trie(str,len,i);
}AC::Build_Fail();
T::solve();
return ;
}
BZOJ 3881 [COCI2015]Divljak (Trie图+Fail树+树链的并+树状数组维护dfs序)的更多相关文章
- BZOJ3881[Coci2015]Divljak——AC自动机+树状数组+LCA+dfs序+树链的并
题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...
- BZOJ 3881: [Coci2015]Divljak [AC自动机 树链的并]
3881: [Coci2015]Divljak 题意:添加新文本串,询问某个模式串在多少种文本串里出现过 模式串建AC自动机,考虑添加一个文本串,走到的节点记录下来求树链的并 方法是按dfs序排序去重 ...
- BZOJ 3881 [Coci2015]Divljak(AC自动机+树状数组)
建立AC自动机然后,加入一个串之后考虑这个串的贡献.我们把这个串扔到AC自动机里面跑.最后对经过每一个点到的这个点在fail树的根的路径上的点有1的贡献.求链的并,我们把这些点按DFS序排序,然后把每 ...
- BZOJ 3881: [Coci2015]Divljak
3881: [Coci2015]Divljak Time Limit: 20 Sec Memory Limit: 768 MBSubmit: 553 Solved: 176[Submit][Sta ...
- bzoj 3881 [Coci2015]Divljak fail树+树链的并
题目大意 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: "1 P",Bob往自己的集合里添 ...
- bzoj 3881 [Coci2015]Divljak——LCT维护parent树链并
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3881 对 S 建 SAM ,每个 T 会让 S 的 parent 树的链并答案+1:在 T ...
- bzoj 3881: [Coci2015]Divljak AC自动机
题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=3881 题解: 这道题我想出了三种做法,不过只有最后一种能过. 第一种: 首先我们把所有的 ...
- BZOJ 3881[COCI2015]Divljak (AC自动机+dfs序+lca+BIT)
显然是用AC自动机 先构建好AC自动机,当B中插入新的串时就在trie上跑,对于当前点,首先这个点所代表的串一定出现过,然后这个点指向的fail也一定出现过.那么我们把每个点fail当作父亲,建一棵f ...
- (好题)树状数组+离散化+DFS序+离线/莫队 HDOJ 4358 Boring counting
题目传送门 题意:给你一棵树,树上的每个节点都有树值,给m个查询,问以每个点u为根的子树下有多少种权值恰好出现k次. 分析:首先要对权值离散化,然后要将树形转换为线形,配上图:.然后按照右端点从小到大 ...
随机推荐
- day13 基本的文件操作(好东西)
目录 基本的文件处理 什么是文件 如何使用文件 使用Python写一个小程序控制文件 open(打开文件) read: readline:一次性读取一行 del:删除 close:关闭 write(写 ...
- 解决MYSQL的错误:Got a packet bigger than 'max_allowed_packet' bytes
Mysql 5.1开始遇到的信息包过大问题,当用客户端导入数据的时候,遇到错误代码: 1153 - Got apacket bigger than 'max_allowed_packet' bytes ...
- POJ 2356 Find a multiple( 鸽巢定理简单题 )
链接:传送门 题意:题意与3370类似 注意:注意输出就ok,输出的是集合的值不是集合下标 /***************************************************** ...
- [读书笔记] R语言实战 (一) R语言介绍
典型数据分析的步骤: R语言:为统计计算和绘图而生的语言和环境 数据分析:统计学,机器学习 R的使用 1. 区分大小写的解释型语言 2. R语句赋值:<- 3. R注释: # 4. 创建向量 c ...
- css实现透明的两种方式及其区别
一.opacity:0~1 值越高,透明度越低,下面为示例 选择器{ opacity:0.5 } 选择器匹配到的节点们,包括节点们的孩子节点,都会实现%50透明,另 0.5 可直接写成 .5 二.rg ...
- LaTeX 基本的公式符号命令
本系列文章由 @YhL_Leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/50240237 下面列出一些基本的LaT ...
- DataTables warning: table id=dataTable - Requested unknown parameter 'acceptId' for row 0. For more
重点内容 DataTables warning: table id=dataTable - Requested unknown parameter 'acceptId' for row 0. For ...
- 【万里征程——Windows App开发】控件大集合2
以下再来看看一些前面还没有讲过的控件,只是控件太多以至于无法所有列出来,大家仅仅好举一反三啦. Button 前面最经常使用的控件就是Button啦,Button另一个有意思的属性呢.当把鼠标指针放在 ...
- 通过 KVM+virt-manager配置双屏虚拟机(两套键盘。鼠标)
感谢朋友支持本博客,欢迎共同探讨交流,因为能力和时间有限,错误之处在所难免,欢迎指正! 假设转载.请保留作者信息. 博客地址:http://blog.csdn.net/qq_21398167 原博文地 ...
- Popupwindow 显示, 其它背景变暗。 并加上点击事件 ~ (用于记录)
public class MainActivity extends Activity implements OnClickListener { protected int mScreenWidth; ...