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次. 分析:首先要对权值离散化,然后要将树形转换为线形,配上图:.然后按照右端点从小到大 ...
随机推荐
- ZBrush中物体的显示与隐藏
在ZBrush®中除了遮罩功能可以对局部网格进行编辑外,通过显示和隐藏局部网格也可以对局部进行控制.选择网格的控制都是手动操作,在软件中并没有相应的命令进行操作.选择局部网格的工作原理也很简单,即被选 ...
- day19-2 生成器,递归函数
目录 生成器 有关yield的理解 实现range()函数 生成器表达式 递归 思考 斐波那契额 汉诺塔 二分法 生成器 自定义的迭代器 yield关键字: 和return一样,接收值,但不终止函数 ...
- 蓝桥杯_基础训练_Sine之舞
基础练习 Sine之舞 时间限制:1.0s 内存限制:512.0MB 问题描述 最近FJ为他的奶牛们开设了数学分析课,FJ知道若要学好这门课,必须有一个好的三角函数基本功.所以他准备和奶牛们做 ...
- Linux磁盘分区--MBR分区
今天心情不高兴,做IT不容易被公司重视,一定要速度学会运营,成为一个高逼格的技术男. 今天我要熟练掌握linux系统分区的能力.大家都知道,linux系统分区有两种分区格式:GTP和MBR. MBR作 ...
- [luogu] P2569 [SCOI2010]股票交易 (单调队列优化)
P2569 [SCOI2010]股票交易 题目描述 最近 \(\text{lxhgww}\) 又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,\(\te ...
- VUE:列表的过滤与排序
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 字符拆分存入Map计算单词的个数
///计算从命令行输入单词的种类与个数//Map<key,Value>Key-->单词:Value-->数量
- COGS——T 1175. [顾研NOIP] 旅游电车
http://www.cogs.pro/cogs/problem/problem.php?pid=1175 ★★☆ 输入文件:buss.in 输出文件:buss.out 简单对比时间限制: ...
- java mail邮件发送(带附件) 支持SSL
java mail邮件发送(带附件)有三个类 MailSenderInfo.java package mail; import java.util.Properties; import java.ut ...
- html表格设计
html部分,biaoge.html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " ...