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
********************/

猜你喜欢

转载自www.cnblogs.com/acjiumeng/p/9293240.html