【dfs序+AC自动机+树状数组】BZOJ2434-[Noi2011]阿狸的打字机
【题目大意】
输入一个字符串,其中:(1)a..z:在字符串末尾添加当前字符(2)P:输出当前字符串(3)B:从当前字符串末尾删去一个字符。
给出m组查询,输出第i个输出的字符串在第j个输出的字符串内出现了几次。
【思路】
卡了好久,写完不想调试,调试完不想提交,期间颓颓颓地弄了下博客的界面,弄成了粉嫩少女风(划掉)。结果提交完1A有点迷醉迷醉的……
首先我们要借用BZOJ3172的结论:★←戳这里,这个结论66666,是本次解题的关键。
“建立AC自动机,对于路径上的每一个点sum++,表示出现的次数。fail指针指向的后缀,如果从fail指针指向的点开始方向建立fail树,其子树的sum之和就等于以它作为后缀的串的总数,相当于它在文章中出现的个数。”
显然我们要把m组询问(i,j)调换位置,同一组j,对i建立一个链表存放。为什么要这么做呢?先继续往下看。
首先,我们建立一个AC自动机,并建立fail树。这里和一般的建立有点区别,因为有删除操作,可以用一个栈来维护当前位于Trie的位置,如果B删除就弹出栈顶,如果为字母就建立新节点并压入栈中,如果是P就在当前位置打上ed的标记,表示这是第ed次打印的字符终止位置。
由于树中节点和子树的dfs序是连续的,我们跑一次dfs记录下fail树上每个点的dfs序,记录下第i个输出字符串,它的末尾节点及其子树在dfs序中的start和end位置。
最后,重新跑一次Trie,和先前一样用栈维护。如果遇到B,就将当前节点-1,弹出栈顶;遇到字母就将当前节点+1;如果遇到P,说明现在恰巧输出了第j个字符串,枚举每一个查询中的i,查询结果=当前i对应的节点和它子树之和。
没错,这是一个单点修改,区间求和,可以用树状数组来维护一下,每个节点在树状数组中的位置就等于它的dfs序。那么当前i对应的节点及其子树之和=sum[start[i]..end[i]],搞定!
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define lnum 26
using namespace std;
const int MAXN=+;
int ppos[MAXN];//第i个P对应的栈顶位置编号
char str[MAXN];
int m,len,step,cnt=,e[MAXN],start[MAXN],end[MAXN],ans[MAXN];
struct ACauto
{
ACauto* next[lnum];
ACauto* fail;
int id,ed,order;
ACauto()
{
for (int i=;i<lnum;i++) next[i]=NULL;
fail=NULL;
id=++cnt;
}
};
struct node
{
int to,id;
};
ACauto* rt=new ACauto();
ACauto* p[MAXN];//编号为i的节点指向的位置
vector<node> Q[MAXN];
vector<int> E[MAXN]; void addedge(int u,int v)
{
E[u].push_back(v);
} int lowbit(int x)
{
return (x&(-x));
} void modify(int p,int x)
{
int i=p;
while (i<=len)
{
e[i]+=x;
i+=lowbit(i);
}
} int sum(int p)
{
int s=;
int i=p;
while (i>)
{
s+=e[i];
i-=lowbit(i);
}
return s;
} void init()
{
scanf("%s",str);
len=strlen(str);
int top=,n=;
ACauto* stack[MAXN];
stack[++top]=p[]=rt;//不要忘记给p[1]赋值
for (int i=;i<len;i++)
{
if (str[i]=='P')
{
stack[top]->ed=++n;
ppos[n]=stack[top]->id;
}
else if (str[i]=='B') top--;
else
{
int index=str[i]-'a';
if (stack[top]->next[index]==NULL)
{
stack[top]->next[index]=new ACauto();
p[cnt]=stack[top]->next[index];
}
stack[++top]=stack[top-]->next[index];
}
} scanf("%d",&m);
for (int i=;i<m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
Q[y].push_back((node){ppos[x],i});
}
} void buildfail()
{
queue<ACauto*> que;
que.push(rt);
while (!que.empty())
{
ACauto* head=que.front();que.pop();
for (int i=;i<lnum;i++)
{
if (head->next[i]!=NULL)
{
if (head==rt)
{
head->next[i]->fail=rt;
addedge(rt->id,head->next[i]->id);
}
else
{
ACauto* tmp=head->fail;
while (tmp!=NULL)
{
if (tmp->next[i]!=NULL)
{
head->next[i]->fail=tmp->next[i];
addedge(tmp->next[i]->id,head->next[i]->id);
break;
}
else tmp=tmp->fail;
}
if (tmp==NULL)
{
head->next[i]->fail=rt;
addedge(rt->id,head->next[i]->id);
}
}
que.push(head->next[i]);
}
}
}
} void dfs(int pos)
{
ACauto* tmp=p[pos];
tmp->order=++step;
if (tmp->ed) start[tmp->ed]=step;
for (int i=;i<E[pos].size();i++) dfs(E[pos][i]);
if (tmp->ed) end[tmp->ed]=step;
} void query()
{
memset(e,,sizeof(e));
int top=,n=;
ACauto* stack[MAXN];
stack[++top]=rt;
for (int i=;i<len;i++)
{
if (str[i]=='P')
{
n++;
for (int i=;i<Q[n].size();i++)
{
ACauto* to=p[Q[n][i].to];
ans[Q[n][i].id]=sum(end[to->ed])-sum(start[to->ed]-);
}
}
else if (str[i]=='B')
{
modify(stack[top]->order,-);
top--;
}
else
{
int index=str[i]-'a';
stack[++top]=stack[top-]->next[index];
modify(stack[top]->order,);
}
}
} void printans()
{
for (int i=;i<m;i++) printf("%d\n",ans[i]);
} int main()
{
init();
buildfail();
dfs(rt->id);
query();
printans();
return ;
}
【dfs序+AC自动机+树状数组】BZOJ2434-[Noi2011]阿狸的打字机的更多相关文章
- 【BZOJ】2434: [Noi2011]阿狸的打字机 AC自动机+树状数组+DFS序
[题意]阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小写 ...
- BZOJ.2434.[NOI2011]阿狸的打字机(AC自动机 树状数组 DFS序)
题目链接 首先不需要存储每个字符串,可以将所有输入的字符依次存进Trie树,对于每个'P',记录该串结束的位置在哪,以及当前节点对应的是第几个串(当前串即根节点到当前节点):对于'B',只需向上跳一个 ...
- 洛谷P2414 阿狸的打字机 [NOI2011] AC自动机+树状数组/线段树
正解:AC自动机+树状数组/线段树 解题报告: 传送门! 这道题,首先想到暴力思路还是不难的,首先看到y有那么多个,菜鸡如我还不怎么会可持久化之类的,那就直接排个序什么的然后按顺序做就好,这样听说有7 ...
- BZOJ3881[Coci2015]Divljak——AC自动机+树状数组+LCA+dfs序+树链的并
题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...
- 洛谷P2414 阿狸的打字机【AC自动机】【fail树】【dfs序】【树状数组】
居然真的遇上了这种蔡队题.瑟瑟发抖. 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. 题目描述 打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿 ...
- CoderForces 163E e-Government(AC自动机+树状数组维护fail树的dfs序)
E. e-Government time limit per test 1 second memory limit per test 256 megabytes input standard inpu ...
- BZOJ2434: [Noi2011]阿狸的打字机(AC自动机 树状数组)
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 4140 Solved: 2276[Submit][Status][Discuss] Descript ...
- [BZOJ2434][Noi2011]阿狸的打字机 AC自动机+树状数组+离线
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2434 题目中这种多个串匹配的问题,一下子就想到了AC自动机.然后发现如果要建立AC自动机, ...
- HDU 6096 String(AC自动机+树状数组)
题意 给定 \(n\) 个单词,\(q\) 个询问,每个询问包含两个串 \(s_1,s_2\),询问有多少个单词以 \(s_1\) 为前缀, \(s_2\) 为后缀,前后缀不能重叠. \(1 \leq ...
随机推荐
- JAVA Frame 响应窗口关闭事件
/* * To change this license header, choose License Headers in Project Properties. * To change this t ...
- recycleView实现item点击更改该item颜色,其它item颜色变回
项目中需要横向滚动效果,按照以前的思路,我会写一个ScrollView,里边加一个LinearLayout,在代码中动态加入控件,然后动态删除或者改变颜色,现在android有了新控件Recycler ...
- 计算机网络课设之基于UDP协议的简易聊天机器人
前言:2017年6月份计算机网络的课设任务,在同学的帮助和自学下基本搞懂了,基于UDP协议的基本聊天的实现方法.实现起来很简单,原理也很简单,主要是由于老师必须要求使用C语言来写,所以特别麻烦,而且C ...
- python中requests库中文乱码问题
当使用这个库的时候经常会出现各种乱码的情况. 首先要知道: text返回的是处理过的unicode的数据. content返回的是bytes的原始数据 也就是说r.content比r.text更加节省 ...
- iptables 操作
iptables --list 查看列表 iptables删除规则 iptables -nL --line-number Chain INPUT (policy ACCEPT)num target p ...
- 2017多校第6场 HDU 6096 String AC自动机
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6096 题意:给了一些模式串,然后再给出一些文本串的不想交的前后缀,问文本串在模式串的出现次数. 解法: ...
- 使用IDEA从github中下载fastdfs-client-java
由于在pom文件中加入依赖坐标无法将fastdfs-client-java下载下来,后来通过查资料,发现在中央仓库中没有定义该坐标.为此,使用idea从github下载fastdfs-client-j ...
- pypcap 安装
1.下载winpcap开发包 https://www.winpcap.org/devel.htm 下载https://github.com/pynetwork/pypcap/releases最新发布的 ...
- Author name disambiguation using a graph model with node splitting and merging based on bibliographic information
Author name disambiguation using a graph model with node splitting and merging based on bibliographi ...
- LeetCode解题报告—— Search in Rotated Sorted Array & Search for a Range & Valid Sudoku
1. Search in Rotated Sorted Array Suppose an array sorted in ascending order is rotated(轮流,循环) at so ...