bzoj2434: [Noi2011]阿狸的打字机 ac自动机+树状数组
bzoj2434
阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。打字机上只有28个按键,分别印有26个小写英文字母和'B'、'P'两个字母。
经阿狸研究发现,这个打字机是这样工作的:
l 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后)。
l 按一下印有'B'的按键,打字机凹槽中最后一个字母会消失。
l 按一下印有'P'的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失。
例如,阿狸输入aPaPBbP,纸上被打印的字符如下:
a
aa
ab
我们把纸上打印出来的字符串从1开始顺序编号,一直到n。打字机有一个非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数(x,y)(其中1≤x,y≤n),打字机会显示第x个打印的字符串在第y个打印的字符串中出现了多少次。
阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助他么?
Input
输入的第一行包含一个字符串,按阿狸的输入顺序给出所有阿狸输入的字符。
第二行包含一个整数m,表示询问个数。
接下来m行描述所有由小键盘输入的询问。其中第i行包含两个整数x, y,表示第i个询问为(x, y)。
Output
输出m行,其中第i行包含一个整数,表示第i个询问的答案。
先建成ac自动机,离线所有查询,记录在树上的终点,把fail树抠出来,先建成dfs序,然后在tire图上跑,当跑到x节点时,root->x节点每个权值为1,(进加1,出减1即可,树状数组单点加),然后利用之前的dfs序查询当前节点fail上的子树总权值和是多少(树状数组查询),因为x在fail树的子树任意节点通过fail上暴跳可以到达x,此时加到的每一个点又是root->x的点,就说明root->x中的节点通过在fail树上暴跳能到达x,记录答案输出即可
这题还有一个问题就是不能先处理出所有子串,插入直接在trie树上跑就好了,需要记录一个fa,p就打个标记,b就跳fa,否则就向下跳
/**************************************************************
Problem: 2434
User: walfy
Language: C++
Result: Accepted
Time:1120 ms
Memory:171844 kb
****************************************************************/
//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pi acos(-1.0)
#define ll long long
#define vi vector<int>
#define mod 1000000007
#define C 0.5772156649
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pii pair<int,int>
#define cd complex<double>
#define ull unsigned long long
#define base 1000000000000000000
#define fio ios::sync_with_stdio(false);cin.tie(0)
using namespace std;
const double eps=1e-6;
const int N=1000000+10,maxn=5000+10,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f;
char s[N];
vector<int>trie[N],ftree[N];
vector<pair<int,int> >qu[N];
struct ACM{
int tot,root;
int Next[N][26],id[N],fail[N],fa[N];
int newnode()
{
for(int i=0;i<26;i++)Next[tot][i]=-1;
id[tot]=0;
return tot++;
}
void init()
{
tot=0;
root=newnode();
}
void ins()
{
int now=root,n=strlen(s),co=0;
for(int i=0;i<n;i++)
{
if('a'<=s[i]&&s[i]<='z')
{
if(Next[now][s[i]-'a']==-1)
{
Next[now][s[i]-'a']=newnode();
trie[now].pb(Next[now][s[i]-'a']);
}
fa[Next[now][s[i]-'a']]=now;
now=Next[now][s[i]-'a'];
}
else if(s[i]=='P')id[++co]=now;//,printf("%d %d\n",co,now);
else now=fa[now];
}
}
void build()
{
queue<int>q;
fail[root]=root;
for(int i=0;i<26;i++)
{
if(Next[root][i]==-1)Next[root][i]=root;
else
{
fail[Next[root][i]]=root;
ftree[root].pb(Next[root][i]);
q.push(Next[root][i]);
}
}
while(!q.empty())
{
int now=q.front();q.pop();
for(int i=0;i<26;i++)
{
if(Next[now][i]==-1)Next[now][i]=Next[fail[now]][i];
else
{
fail[Next[now][i]]=Next[fail[now]][i];
ftree[Next[fail[now]][i]].pb(Next[now][i]);
q.push(Next[now][i]);
}
}
}
}
}ac;
struct BIT{
int sum[N];
void add(int i,int v)
{
for(;i<N;i+=i&(-i))sum[i]+=v;
}
int query(int i)
{
int ans=0;
for(;i;i-=i&(-i))ans+=sum[i];
return ans;
}
}b;
int l[N],r[N],res=0,ans[N];
void dfsfail(int u)
{
// printf("%d \n",u);
l[u]=++res;
for(int i=0;i<ftree[u].size();i++)
{
int x=ftree[u][i];
dfsfail(x);
}
r[u]=res;
}
void dfstrie(int u)
{
// printf("%d\n",u);
b.add(l[u],1);
for(int i=0;i<qu[u].size();i++)
{
int x=qu[u][i].fi;
ans[qu[u][i].se]=b.query(r[x])-b.query(l[x]-1);
}
for(int i=0;i<trie[u].size();i++)
{
int x=trie[u][i];
dfstrie(x);
}
b.add(l[u],-1);
}
int main()
{
scanf("%s",s);
ac.init();
ac.ins();
ac.build();
// for(int i=0;i<ac.tot;i++)
// {
// for(int j=0;j<ftree[i].size();j++)
// printf("%d ",ftree[i][j]);
// printf("---%d\n",i);
// }
int m;scanf("%d",&m);
for(int i=0;i<m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
x=ac.id[x],y=ac.id[y];
qu[y].pb(mp(x,i));
}
dfsfail(ac.root);
dfstrie(ac.root);
for(int i=0;i<m;i++)printf("%d\n",ans[i]);
return 0;
}
/********************
aPaPBbP
3
1 2
1 3
2 3
********************/