zoukankan      html  css  js  c++  java
  • 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
    ",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 
    ",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
    ",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
    ",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
    ",ans[i]);
        return 0;
    }
    /********************
    aPaPBbP
    3
    1 2
    1 3
    2 3
    ********************/
    
  • 相关阅读:
    ECMAScript6 入门 函数的扩展
    ECMAScript6 入门-let与const命令
    编码规范
    webpack常用插件
    JS与CSS那些特别小的知识点区别
    常见数组方法及细节
    JS库
    Object冷知识
    html5-语义化标签
    Css继承属性和非继承属性
  • 原文地址:https://www.cnblogs.com/acjiumeng/p/9293240.html
Copyright © 2011-2022 走看看