BZOJ3881 : [Coci2015]Divljak
对Alice的所有串构造AC自动机,并建出Fail树
每当Bob添加一个串时,在AC自动机上走,每走到一个点,就把它到根路径上所有点的答案+1
需要注意的是每次操作,相同的点只能被加一次
所以在需要操作的点构成的虚树上进行修改操作,避免重复修改
对于修改,x到根路径上所有点答案+1等价于在x点打上一个标记,对于所有祖先都有效
由此将问题转化为单点修改,子树查询
树状数组维护
注意到关键点其实只有n个,所以可以一开始先对这n个点求一次虚树来降低常数
时间复杂度$O(L\log L)$,L为所有串的长度之和
#include<cstdio>
#include<algorithm>
#define N 2000010
using namespace std;
int tot,son[N][26],f[N],v[N],nxt[N],g[N],ed,q[N],h=1,t=1;
int size[N],heavy[N],d[N],top[N],st[N],en[N],dfn,bit[N],fin[100010],fir[N],fa[N];
int m,a[N],b[N];bool vis[N],have[N];
int n,Q,i,k,j,x,op,l;
int need[N],cn;
char s[N],c;
inline void read(int&a){while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
inline void readstr(){for(l=0;((c=getchar())>='a')&&(c<='z');s[l++]=c);}
inline bool cmp(int x,int y){return st[x]<st[y];}
inline void ins(int p){
for(int x=0,i=0,w;i<l;i++){
if(!son[x][w=s[i]-'a'])son[x][w]=++tot;x=son[x][w];
if(i==l-1)fin[p]=x;
}
}
inline void add(int x,int y){fa[y]=x;v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void dfs(int x){
st[x]=++dfn;d[x]=d[fa[x]]+1;size[x]=1;heavy[x]=-1;
for(int i=g[x];i;i=nxt[i])if(v[i]!=fa[x]){
dfs(v[i]);size[x]+=size[v[i]];
if(heavy[x]<0||size[v[i]]>size[heavy[x]])heavy[x]=v[i];
}
en[x]=dfn;
}
void dfs2(int x,int y){
top[x]=y;
if(~heavy[x])dfs2(heavy[x],y);
for(int i=g[x];i;i=nxt[i])if(v[i]!=heavy[x]&&v[i]!=fa[x])dfs2(v[i],v[i]);
}
void dfs3(int x,int y){
if(vis[x])y=x;
fir[x]=y;
for(int i=g[x];i;i=nxt[i])if(v[i]!=fa[x])dfs3(v[i],y);
}
inline int lca(int x,int y){
for(;top[x]!=top[y];x=fa[top[x]])if(d[top[x]]<d[top[y]])swap(x,y);
return d[x]<d[y]?x:y;
}
inline void modify(int x,int y){for(;x<=dfn;x+=x&-x)bit[x]+=y;}
inline int sum(int x){t=0;for(;x;x-=x&-x)t+=bit[x];return t;}
inline void match(){
for(int x=0,i=m=0,w;i<l;i++){
w=s[i]-'a';
while(x&&!son[x][w])x=f[x];x=son[x][w];
if(!vis[fir[x]])vis[a[++m]=fir[x]]=1;
}
}
int main(){
for(read(n),i=1;i<=n;i++)readstr(),ins(i);
f[0]=-1;
while(h<=t)for(x=q[h++],i=0;i<26;i++)if(son[x][i])for(q[++t]=son[x][i],j=f[x];~j;j=f[j])if(x&&son[j][i]){f[son[x][i]]=son[j][i];break;}
for(i=1;i<=tot;i++)add(f[i],i);
dfs(0),dfs2(0,0);
vis[0]=m=1;
for(i=1;i<=n;i++)if(!vis[fin[i]])vis[a[++m]=fin[i]]=1;
sort(a+1,a+m+1,cmp);
for(cn=m,i=1;i<m;i++)if(!vis[x=lca(a[i],a[i+1])])vis[a[++cn]=x]=1;
dfs3(0,0);
for(ed=i=0;i<=tot;i++)g[i]=0;
m=cn,sort(a+1,a+m+1,cmp);
for(q[t=1]=0,i=2;i<=m;q[++t]=a[i++]){
while(st[a[i]]<st[q[t]]||en[a[i]]>en[q[t]])t--;
add(q[t],a[i]);
}
for(i=1;i<=m;i++)vis[a[i]]=0;
dfs(dfn=cn=0);dfs2(0,0);
read(Q);
while(Q--){
read(op);
if(op==1){
readstr();
match();
sort(a+1,a+m+1,cmp);
for(tot=m,i=1;i<m;i++)if(!vis[x=lca(a[i],a[i+1])])vis[a[++tot]=x]=1;
m=tot,sort(a+1,a+m+1,cmp);
if(!have[x=a[1]])have[x]=1,b[x]=0,need[++cn]=x;b[x]++;
for(q[t=1]=a[1],i=2;i<=m;q[++t]=a[i++]){
while(st[a[i]]<st[q[t]]||en[a[i]]>en[q[t]])t--;
if(!have[x=q[t]])have[x]=1,b[x]=0,need[++cn]=x;b[x]--;
if(!have[x=a[i]])have[x]=1,b[x]=0,need[++cn]=x;b[x]++;
}
for(i=1;i<=m;i++)vis[a[i]]=0;
}else{
if(cn){
for(i=1;i<=cn;i++)x=need[i],modify(st[x],b[x]),have[x]=b[x]=0;
cn=0;
}
read(x),x=fin[x],printf("%d\n",sum(en[x])-sum(st[x]-1));
}
}
return 0;
}
BZOJ3881 : [Coci2015]Divljak的更多相关文章
- BZOJ3881[Coci2015]Divljak——AC自动机+树状数组+LCA+dfs序+树链的并
题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...
- BZOJ3881 Coci2015 Divljak fail树+差分
题目大意,给出两个字符串集合S和T,向T中添加字符串,查询S_i在T中有几个字符串出现过.一看这种多字符串匹配问题,我们联想到了AC自动机,做法就是,对于S集合我们建立一个AC自动机,建出fail树, ...
- 【BZOJ3881】[Coci2015]Divljak fail树+树链的并
[BZOJ3881][Coci2015]Divljak Description Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操 ...
- 【BZOJ-3881】Divljak AC自动机fail树 + 树链剖分+ 树状数组 + DFS序
3881: [Coci2015]Divljak Time Limit: 20 Sec Memory Limit: 768 MBSubmit: 508 Solved: 158[Submit][Sta ...
- BZOJ 3881: [Coci2015]Divljak [AC自动机 树链的并]
3881: [Coci2015]Divljak 题意:添加新文本串,询问某个模式串在多少种文本串里出现过 模式串建AC自动机,考虑添加一个文本串,走到的节点记录下来求树链的并 方法是按dfs序排序去重 ...
- BZOJ 3881: [Coci2015]Divljak
3881: [Coci2015]Divljak Time Limit: 20 Sec Memory Limit: 768 MBSubmit: 553 Solved: 176[Submit][Sta ...
- 【bzoj3881】[Coci2015]Divljak AC自动机+树链的并+DFS序+树状数组
题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...
- [Coci2015]Divljak
题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...
- bzoj 3881: [Coci2015]Divljak AC自动机
题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=3881 题解: 这道题我想出了三种做法,不过只有最后一种能过. 第一种: 首先我们把所有的 ...
随机推荐
- php __set() __get() __isset() __unset()四个方法的应用
一般来说,总是把类的属性定义为private,这更符合现实的逻辑.但是,对属性的读取 和赋值操作是非常频繁的,因此在PHP5 中,预定义了两个函数“__get()”和“__set()”来获 取和赋值其 ...
- Redis学习手册(Sorted-Sets数据类型)
一.概述: Sorted-Sets和Sets类型极为相似,它们都是字符串的集合,都不允许重复的成员出现在一个Set中.它们之间的主要差别是Sorted-Sets中的每一个成员都会有一个分数(score ...
- 【架构】浅谈web网站架构演变过程
浅谈web网站架构演变过程 前言 我们以javaweb为例,来搭建一个简单的电商系统,看看这个系统可以如何一步步演变. 该系统具备的功能: 用户模块:用户注册和管理 商品模块:商品展示和管 ...
- spring中context:property-placeholder/元素
1.有些参数在某些阶段中是常量 比如 :a.在开发阶段我们连接数据库时的连接url,username,password,driverClass等 b.分布式应用中client端访问server端所用的 ...
- 44. log(n)求a的n次方[power(a,n)]
[题目] 实现函数double Power(double base, int exponent),求base的exponent次方,不需要考虑溢出. [分析] 这是一道看起来很简单的问题,很容易写出如 ...
- python将json格式的数据转换成文本格式的数据或sql文件
python如何将json格式的数据快速的转化成指定格式的数据呢?或者转换成sql文件? 下面的例子是将json格式的数据准换成以#_#分割的文本数据,也可用于生成sql文件. [root@bogon ...
- iOS 中的Push Notifications简单实现(APNS)
Android中的通知只有一种,就是Local Notifications,而iOS中除了Local Notifications外,还有一种Push Notifications.ios的这2种noti ...
- eclipse字体的设置
eclipse的默认字体太小,所以设置的大一些比较清楚,方法很简单,单击菜单栏的"Window"选择"Preferences",如下图: 然后左侧依次选择Gen ...
- Python多线程(2)——线程同步机制
本文介绍Python中的线程同步对象,主要涉及 thread 和 threading 模块. threading 模块提供的线程同步原语包括:Lock.RLock.Condition.Event.Se ...
- 【USACO】numtri
给一颗数字树,让找一条数字和最大的路径.一下子就想起刚学不久的回溯法了.照着写了个代码,调了调搞通了.在小数据的情况下是对的,但是在test 6 树有199层的时候溢出了. #include < ...