码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj2434: [Noi2011]阿狸的打字机

时间:2018-03-31 10:57:11      阅读:136      评论:0      收藏:0      [点我收藏+]

标签:insert   一起   ==   bit   数组   turn   col   cstring   pac   

可以说也是很迷了。最近写的字符串的题都很迷。。

首先看到路牌先写板子AC机,然后迷

然后???

回忆一下fail的定义:fail[i]到根形成的字符串是i到根形成的字符串的后缀。

那么大力跳fail硬搞

那么题目询问就变成了求在第y个字符串的那条路径上,有多少个节点fail指向的是第x个字符串的最后一个节点。

根据题解考虑离线搞。

排序一下,这样我们就可以把询问相同y字符串放在一起做。

还是不会做。先把后缀树建出来吧。

诶好像在底部的点都可以对上层的点作出贡献诶,也就是说假如y中的一个点的fail指向x的结尾,那么这个点肯定在x的结尾点的子树里面,那是不是dfs序一下搞个树状数组求答案就行了?

那就再for一次原串,遇到字符就给它+1,删就-1,到了P就看下现在是第几个字符串,这个时候的树状数组就已经把当前字符串的值记录下来了,找到所对应的询问的x串结尾在哪,把它子树的值求出来就行了。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;

char ss[110000];int slen;
int cnt,chuan[110000];
struct Trie
{
    int w[30],fa,fail;
}tr[510000];int trlen;
void insert()
{
    scanf("%s",ss+1);slen=strlen(ss+1);
    
    trlen=0;cnt=0;
    int now=0;
    for(int i=1;i<=slen;i++)
    {
        if(ss[i]==B)now=tr[now].fa;
        else if(ss[i]==P)chuan[++cnt]=now;
        else
        {
            int x=ss[i]-a+1;
            if(tr[now].w[x]==0)
                tr[now].w[x]=++trlen, tr[trlen].fa=now;
            now=tr[now].w[x];
        }
    }
}
int list[510000];
void bfs()
{
    int head=1,tail=2;list[head]=0;
    while(head!=tail)
    {
        int now=list[head];
        for(int x=1;x<=26;x++)
        {
            int son=tr[now].w[x];
            if(son!=0)
            {
                if(now==0)tr[son].fail=0;
                else
                {
                    int p=tr[now].fail;
                    while(p!=0&&tr[p].w[x]==0)p=tr[p].fail;
                    tr[son].fail=tr[p].w[x];
                }
                list[tail]=son;
                tail++;if(tail==505000)tail=1;
            }
        }
        head++;if(head==505000)head=1;
    }
}

//-----------------AC_machine------------------------

struct node
{
    int x,y,next;
}a[510000];int len,last[510000];
void ins(int x,int y)
{
    len++;
    a[len].x=x;a[len].y=y;
    a[len].next=last[x];last[x]=len;
}
int z,l[510000],r[510000];
void get_dfs(int x)
{
    l[x]=++z;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        get_dfs(y);
    }
    r[x]=z;
}
void makefailtree()
{
    len=0;memset(last,0,sizeof(last));
    for(int i=1;i<=trlen;i++)ins(tr[i].fail,i);
    z=0;get_dfs(0);
}

//-------------make tree and get dfs---------------------

int s[510000];
int lowbit(int x){return x&-x;}
void change(int x,int k)
{
    while(x<=z)
    {
        s[x]+=k;
        x+=lowbit(x);
    }
}
int getsum(int x)
{
    int ret=0;
    while(x>=1)
    {
        ret+=s[x];
        x-=lowbit(x);
    }
    return ret;
}

//--------------bit-----------------------

struct query
{
    int x,y,id;
}q[110000];int tip;
bool cmp(query n1,query n2){return n1.y<n2.y;}
int as[110000];
int main()
{
    freopen("type.in","r",stdin);
    freopen("type.out","w",stdout);
    
    insert();bfs();
    makefailtree();
    
    int Q;
    scanf("%d",&Q);
    for(int i=1;i<=Q;i++)
        scanf("%d%d",&q[i].x,&q[i].y),q[i].id=i;
    sort(q+1,q+Q+1,cmp);
    
    tip=1;int p=0,num=0;
    for(int i=1;i<=slen;i++)
    {
        if(ss[i]==P)
        {
            num++;
            while(q[tip].y==num)
            {
                int u=chuan[q[tip].x];
                as[q[tip].id]=getsum(r[u])-getsum(l[u]-1);
                tip++;
            }
        }
        else if(ss[i]==B)
            change(l[p],-1),p=tr[p].fa;
        else 
            p=tr[p].w[ss[i]-a+1],change(l[p],1);
    }
    
    for(int i=1;i<=Q;i++)printf("%d\n",as[i]);
    return 0;
}

 

bzoj2434: [Noi2011]阿狸的打字机

标签:insert   一起   ==   bit   数组   turn   col   cstring   pac   

原文地址:https://www.cnblogs.com/AKCqhzdy/p/8681101.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!