• BZOJ2434: [Noi2011]阿狸的打字机


    【传送门:BZOJ2434


    简要题意:

      给出一个串,然后这个串有28种字符,26个小写英文字母和'B','P'两个字母

      我们定义一个模式串(一开始这个串是空的)

      假如当前输入的字符是小写英文字母的话,就在模式串的末尾加上这个字母

      如果是'B',就把模式串的末尾给去掉

      如果是'P',就把当前模式串当作一个新的字符串

      然后给出m个询问,每个询问输入x,y,输出第x个字符串在第y个字符串中出现的次数


    题解:

      处理x字符串在y字符串出现的次数,很容易想到fail树

      一开始想着把y字符串的结尾字符在trie树上的位置开始,往上找,找到的点的fail指针如果指向x字符串的结尾字符的话,ans就++

      但是这样做的时间复杂度是O(mn),显然会超时

      这时,就要想更快的离线的方法...

      不会!!!!

      果断膜题解(以下来自神犇

      发现可以利用fail树上的一个节点及其子树在dfs序中是连续的一段,那么我们可以用一个树状数组来维护x串末尾节点及其子树上有多少个属于y串的节点,那么我们可以得到一个离线算法:对fail树遍历一遍,得到一个dfs序,再维护一个树状数组,对原trie树进行遍历,每访问一个节点,就修改树状数组,对树状数组中该节点的dfs序起点的位置加上1,每往回走一步,就减去1。如果访问到了一个y字串的末尾节点,枚举询问中每个y串对应的x串,查询树状数组中x串末尾节点从dfs序中的起始位置到结束位置的和,并记录答案


    参考代码:

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<cmath>
    using namespace std;
    struct node
    {
        int c[27],fail,f;
        node()
        {
            fail=f=0;
            memset(c,-1,sizeof(c));
        }
    }t[110000];
    int tot,n;
    char st[110000];
    int s[110000];
    int end[110000];
    void bt(int root,int z)
    {
        int x=root,len=strlen(st+1);
        for(int i=1;i<=len;i++)
        {
            int y=st[i]-'a'+1;
            if(t[x].c[y]==-1)
            {
                t[x].c[y]=++tot;
            }
            x=t[x].c[y];s[x]++;
        }
        end[z]=x;
    }
    struct edge
    {
        int x,y,next;
    }a[110000];int len,last[110000];
    void ins(int x,int y)
    {
        len++;
        a[len].x=x;a[len].y=y;
        a[len].next=last[x];last[x]=len;
    }
    queue<int> q;
    void bfs()
    {
        int x;
        q.push(0);
        while(q.empty()==0)
        {
            x=q.front();
            for(int i=1;i<=26;i++)
            {
                int son=t[x].c[i];
                if(son==-1)continue;
                if(x==0) t[son].fail=0;
                else
                {
                    int j=t[x].fail;
                    while(j!=0&&t[j].c[i]==-1) j=t[j].fail;
                    t[son].fail=max(t[j].c[i],0);
                }
                ins(t[son].fail,son);
                q.push(son);
            }
            q.pop();
        }
    }
    int l[110000],r[110000],z;
    void dfs(int x)
    {
        l[x]=++z;
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            dfs(y);
        }
        r[x]=z;
    }
    int d[110000];
    int lowbit(int x){return x&-x;}
    int getsum(int x)
    {
        int ans=0;
        while(x!=0)
        {
            ans+=d[x];
            x-=lowbit(x);
        }
        return ans;
    }
    void change(int x,int c)
    {
        while(x<=z)
        {
            d[x]+=c;
            x+=lowbit(x);
        }
    }
    struct qn
    {
        int x,y,id;
    }p[110000];
    bool cmp(qn n1,qn n2)
    {
        return n1.y<n2.y;
    }
    int ans[110000];
    int main()
    {
        tot=0;
        scanf("%s",st+1);
        n=strlen(st+1);
        int x=0;
        for(int i=1;i<=n;i++)
        {
            if(st[i]=='P') end[++len]=x;
            else if(st[i]=='B') x=t[x].f;
            else
            {
                int y=st[i]-'a'+1;
                if(t[x].c[y]==-1)
                {
                    t[x].c[y]=++tot;
                    t[tot].f=x;
                    s[x]++;
                }
                x=t[x].c[y];
            }
        }
        len=0;memset(last,0,sizeof(last));
        bfs();
        z=0;
        dfs(0);
        int m;scanf("%d",&m);
        for(int i=1;i<=m;i++){scanf("%d%d",&p[i].x,&p[i].y);p[i].id=i;}
        sort(p+1,p+m+1,cmp);
        int k=1,cnt=0;x=0;
        for(int i=1;i<=n;i++)
        {
            if(st[i]=='P')
            {
                cnt++;
                while(cnt==p[k].y)
                {
                    ans[p[k].id]=getsum(r[end[p[k].x]])-getsum(l[end[p[k].x]]-1);
                    k++;
                }
            }
            else if(st[i]=='B')
            {
                change(l[x],-1);
                x=t[x].f;
            }
            else
            {
                x=t[x].c[st[i]-'a'+1];
                change(l[x],1);
            }
        }
        for(int i=1;i<=m;i++) printf("%d
    ",ans[i]);
        return 0;
    }

     

  • 相关阅读:
    Eureka系列---【Eureka配置详解】
    bat脚本系列---【自动以管理员身份运行bat脚本】
    bat脚本系列---【批量修改文件名】
    我爱java系列---【微信定时自动发送消息功能】
    我爱java系列---【idea中如何使用git】
    我爱java系列---【Java将字符串的首字母转换大小写】
    我爱java系列---【java对象比较器,用于记录修改操作时修改的具体详情】
    我爱java系列---【项目研发流程——一张图搞定】
    Majority Number III
    G面经prepare: Straight Partition of A Deck of Cards
  • 原文地址:https://www.cnblogs.com/Never-mind/p/8108951.html
Copyright © 2020-2023  润新知