NOI 2011 阿狸的打字机(AC自动机+主席树)
题意
思路
多串匹配,考虑 \(\text{AC}\) 自动机。模拟打字的过程,先建出一棵 \(\text{Trie}\) 树,把它变成自动机。对于每一个询问 \((x,y)\) ,相当于求 \(y\) 在 \(\text{Trie}\) 上的父节点中,有多少个是 \(x\) 在 \(\text{fail}\) 树上的子节点。
不难想到离线,我们对于 \(y\) 记录所有 \(x\) ,求出 \(\text{fail}\) 树上的 \(\text{dfs}\) 序并在 \(\text{Trie}\) 树上 \(\text{dfs}\) ,通过主席树维护遍历到每个点时 \(\text{fail}\) 树 \(\text{dfs}\) 序的信息,每遍历到一个点就把它在 \(\text{fail}\) 树上的 \(\text{dfs}\) 序记进主席树里,并回答在这个点上的所有询问即可。
代码
#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
#define x first
#define y second
using namespace std;
template<typename T,typename _T>inline bool chk_min(T &x,const _T y){return y<x?x=y,1:0;}
template<typename T,typename _T>inline bool chk_max(T &x,const _T y){return x<y?x=y,1:0;}
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+5;
const int NN=N*40;
template<const int maxn,const int maxm>struct Linked_list
{
int head[maxn],to[maxm],nxt[maxm],tot;
Linked_list(){clear();}
void clear(){memset(head,-1,sizeof(head));tot=0;}
void add(int u,int v){to[++tot]=v,nxt[tot]=head[u],head[u]=tot;}
#define EOR(i,G,u) for(int i=G.head[u];~i;i=G.nxt[i])
};
struct ChairmanTree
{
int rt[N],lson[NN],rson[NN],sum[NN];
int tot;
int &operator [](const int x){return rt[x];}
void build()
{
memset(rt,0,sizeof(rt));
sum[tot=0]=lson[0]=rson[0]=0;
}
void create(int &k)
{
sum[++tot]=sum[k],lson[tot]=lson[k],rson[tot]=rson[k];
k=tot;
}
void update(int &k,int x,int val,int l,int r)
{
create(k);
if(l==r){sum[k]+=val;return;}
int mid=(l+r)>>1;
if(x<=mid)update(lson[k],x,val,l,mid);
else update(rson[k],x,val,mid+1,r);
sum[k]=sum[lson[k]]+sum[rson[k]];
}
int query(int k,int L,int R,int l,int r)
{
if(L<=l&&r<=R)return sum[k];
int mid=(l+r)>>1;
if(R<=mid)return query(lson[k],L,R,l,mid);
else if(L>mid)return query(rson[k],L,R,mid+1,r);
else return query(lson[k],L,R,l,mid)+query(rson[k],L,R,mid+1,r);
}
};
Linked_list<N,N>G;
ChairmanTree CT;
int fa[N],son[N][26],ch[N][26],f[N],idx[N];
int L[N],R[N],ord;
int rt,tot;
string str;
int n,m;
vector<pii>vec[N];
int Output[N];
void build(){rt=tot=0;}
void create(int &k)
{
if(!k)
{
k=++tot;
FOR(i,0,25)son[k][i]=ch[k][i]=0;
}
}
void get_fail()
{
queue<int>Q;
while(!Q.empty())Q.pop();
f[rt]=rt;
FOR(i,0,25)
{
if(ch[rt][i])f[ch[rt][i]]=rt,Q.push(ch[rt][i]);
else ch[rt][i]=rt;
}
while(!Q.empty())
{
int u=Q.front();Q.pop();
FOR(i,0,25)
{
if(ch[u][i])f[ch[u][i]]=ch[f[u]][i],Q.push(ch[u][i]);
else ch[u][i]=ch[f[u]][i];
}
}
}
void dfs_fail(int u)
{
L[u]=++ord;
EOR(i,G,u)dfs_fail(G.to[i]);
R[u]=ord;
}
void init(string &str)
{
create(rt);
fa[rt]=rt;
int now=rt;
FOR(i,0,str.length()-1)
{
char a=str[i];
if(a>='a'&&a<='z')
{
if(!ch[now][a-'a'])
{
create(ch[now][a-'a']);
son[now][a-'a']=ch[now][a-'a'];
fa[son[now][a-'a']]=now;
}
now=ch[now][a-'a'];
}
else if(a=='P')
{
n++;
idx[n]=now;
}
else if(a=='B')now=fa[now];
}
}
void dfs_trie(int u)
{
CT.update(CT[u],L[u],1,1,tot);
FOR(i,0,(int)vec[u].size()-1)
{
int x=vec[u][i].x,id=vec[u][i].y;
Output[id]=CT.query(CT[u],L[x],R[x],1,tot);
}
FOR(i,0,25)if(son[u][i])
{
CT[son[u][i]]=CT[u];
dfs_trie(son[u][i]);
}
}
int main()
{
cin>>str>>m;
init(str);
FOR(i,1,m)
{
int x,y;
scanf("%d%d",&x,&y);
vec[idx[y]].push_back(pii(idx[x],i));
}
get_fail();
FOR(i,1,tot)if(f[i]!=i)G.add(f[i],i);
ord=0;dfs_fail(rt);
CT.build();
dfs_trie(rt);
FOR(i,1,m)printf("%d\n",Output[i]);
return 0;
}
NOI 2011 阿狸的打字机(AC自动机+主席树)的更多相关文章
- NOI 2011 阿狸的打字机 (AC自动机+dfs序+树状数组)
题目大意:略(太长了不好描述) 良心LOJ传送门 先对所有被打印的字符串建一颗Trie树 观察数据范围,并不能每次打印都从头到尾暴力建树,而是每遍历到一个字符就在Trie上插入这个字符,然后记录每次打 ...
- BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2545 Solved: 1419[Submit][Sta ...
- 【BZOJ-2434】阿狸的打字机 AC自动机 + Fail树 + DFS序 + 树状数组
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2022 Solved: 1158[Submit][Sta ...
- BZOJ2434:[NOI2011]阿狸的打字机(AC自动机,线段树)
Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...
- BZOJ 2434: [Noi2011]阿狸的打字机 AC自动机+fail树+线段树
Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...
- BZOJ 2434 Luogu P2414 [NOI2011]阿狸的打字机 (AC自动机、树状数组)
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2434 题解: 我写的是离线做法,不知道有没有在线做法. 转化一波题意,\(x\)在AC ...
- BZOJ 2434: [Noi2011]阿狸的打字机( AC自动机 + DFS序 + 树状数组 )
一个串a在b中出现, 那么a是b的某些前缀的后缀, 所以搞出AC自动机, 按fail反向建树, 然后查询(x, y)就是y的子树中有多少是x的前缀. 离线, 对AC自动机DFS一遍, 用dfs序+树状 ...
- BZOJ2434: [Noi2011]阿狸的打字机(AC自动机 树状数组)
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 4140 Solved: 2276[Submit][Status][Discuss] Descript ...
- BZOJ2434[Noi2011]阿狸的打字机——AC自动机+dfs序+树状数组
题目描述 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小 ...
随机推荐
- qDeleteAll 之后必须清空容器
[1]qDeleteAll应用示例 qDeleteAll源码如下: template <typename ForwardIterator> Q_OUTOFLINE_TEMPLATE voi ...
- QtCreator 调试源码
[1]安装源码 声明:要想调试进入Qt源码,必须首先保证我们安装了Qt源码.下面说明安装Qt源码注意事项. 一般安装过程(默认不安装源码): 安装源码过程(需要自己设置,点击“全选”): 综上所述:Q ...
- Linux基础命令---netstat显示网络状态
netstat netstat指令可以显示当前的网络连接.路由表.接口统计信息.伪装连接和多播成员资格等信息. 此命令的适用范围:RedHat.RHEL.Ubuntu.CentOS.SUSE.open ...
- linux yum配置本地iso镜像
1.本地源配置:cdiso.repo 将iso镜像文件中所有内容复制到/public/software/cdrom 中,节点将本地yum指向此处. [root@node19 ~]# vim /etc/ ...
- Codeforce 697A - Pineapple Incident
Ted has a pineapple. This pineapple is able to bark like a bulldog! At time t (in seconds) it barks ...
- P1192 台阶问题
递推问题,要用到递推式: 设f(n)为n个台阶的走法总数,把n个台阶的走法分成k类:第1类:第1步走1阶,剩下还有n-1阶要走,有f(n-1)种方法: 第2类:第1步走2阶,剩下还有n-2阶要走,有f ...
- Zabbix客户端(被监控端)安装配置
1) 创建用户 groupadd zabbix useradd -g zabbix zabbix 2)zabbix软件包下载,安装 zabbix-2.2.6 http://jaist.dl.sourc ...
- linux centos6.5 php5.6 安装PHPUnit 5.2.9 (转)
转自:http://blog.csdn.net/shancunxiaoyazhi/article/details/50765293 操作系统版本:CentOS6.5 PHP版本:5.6 下载phpun ...
- Python爬虫【三】利用requests和正则抓取猫眼电影网上排名前100的电影
#利用requests和正则抓取猫眼电影网上排名前100的电影 import requests from requests.exceptions import RequestException imp ...
- Java动态菜单添加
自己做出来的添加数据库配置好的动态菜单的方法 private void createMenu() { IMenuDAO dao = new MenuDAOImpl(); String sql1 = ...