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次. 分析:首先要对权值离散化,然后要将树形转换为线形,配上图:.然后按照右端点从小到大 ...
随机推荐
- 脚本_求和100以内的正整数.sh
#!bin/bash#功能:求和100以内的正整数#作者:liusingbon#seq 100 可以快速自动生成 100 个整数sum=0for i in $(seq 100)do sum=$[ ...
- bzoj 2648: SJY摆棋子 KDtree + 替罪羊式重构
KDtree真的很妙啊,真的是又好写,作用还多,以后还需更多学习呀. 对于这道题,我们求的是曼哈顿距离的最小值. 而维护的变量和以往是相同的,就是横纵坐标的最小值与最大值. 我们设为一个极为巧妙且玄学 ...
- POJ 3370 Halloween treats( 鸽巢原理简单题 )
链接:传送门 题意:万圣节到了,有 c 个小朋友向 n 个住户要糖果,根据以往的经验,第i个住户会给他们a[ i ]颗糖果,但是为了和谐起见,小朋友们决定要来的糖果要能平分,所以他们只会选择一部分住户 ...
- Spark机器学习之MLlib整理分析
友情提示: 本文档根据林大贵的<Python+Spark 2.0 + Hadoop机器学习与大数据实战>整理得到,代码均为书中提供的源码(python 2.X版本). 本文的可以利用pan ...
- Python数学实现二元一次方程
import cmath import math import sys def get_float(msg,allow_zero): x = None while x is None: try: x ...
- 搭建一套Java开发环境以及使用eclipse从头一步步创建java项目
一.java 开发环境的搭建 在windows 环境下怎么配置环境. 1.首先安装JDK java的sdk简称JDK ,去其官方网站下载JDK. https://www.oracle.com/tech ...
- Lock-less and zero copy messaging scheme for telecommunication network applications
A computer-implemented system and method for a lock-less, zero data copy messaging mechanism in a mu ...
- php+mysql时报错:Unknown column '' in 'field list'解决方案
答案来源:http://jingyan.baidu.com/article/9f7e7ec05c5ad76f281554ab.html 很多人在用php+MySQL做网站往数据库插入数据时发现如下错误 ...
- zzulioj--1633--Happy Thanksgiving Day - Hateable Name(字符串筛选)
1633: Happy Thanksgiving Day - Hateable Name Time Limit: 1 Sec Memory Limit: 128 MB Submit: 75 ...
- xBIM 基础09 WeXplorer 基本应用
系列目录 [已更新最新开发文章,点击查看详细] 在本教程中,将学习如何创建最基本和最直接的查看器. 除了展示建筑模型外,不做其他任何操作.它将只使用内置导航,但是不会对按钮做出事件响应. &l ...