牛客网___阿狸的打字机

链接:https://ac.nowcoder.com/acm/problem/17633
来源:牛客网
 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。

打字机上只有28个按键,分别印有26个小写英文字母和'B'、'P'两个字母。 经阿狸研究发现,这个打字机是这样工作的:

输入小写字母,打字机的一个凹槽中会加入这个字母(按P前凹槽中至少有一个字母)。
按一下印有'B'的按键,打字机凹槽中最后一个字母会消失。
按一下印有'P'的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失(保证凹槽中至少有一个字母)。

例如,阿狸输入aPaPBbP,纸上被打印的字符如下: a aa ab 我们把纸上打印出来的字符串从1开始顺序编号,一直到n。打字机有一个非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数(x,y)(其中1≤x,y≤n),打字机会显示第x个打印的字符串在第y个打印的字符串中出现了多少次。

阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助他么?

输入描述:

输入的第一行包含一个字符串,按阿狸的输入顺序给出所有阿狸输入的字符。

第二行包含一个整数m,表示询问个数。

接下来m行描述所有由小键盘输入的询问。其中第i行包含两个整数x, y,表示第i个询问为(x, y)。

输出描述:

输出m行,其中第i行包含一个整数,表示第i个询问的答案。

示例1

输入

复制

aPaPBbP
3
1 2
1 3
2 3

输出

复制

2
1
0

备注:

 

 

 

题解:一开始不知道怎么处理一个串与一个串的比较,又不会被其他的串的贡献影响,然后就去看别人的代码,发现还是跟上一道string的套路差不多,只是这时的build()的要改一下,不能再让for(int i=0;i<26;i++)if(next[p][i]==0)next[p][i]=next[fail[p]][i];(p为当前节点位置,fail是失配指针)因为我们是一个串与一个串之间的比较,所以我们最后计算时,是一条链一条链的跑,跑完就把之前加的值删除,这样对于在当前的串,其他串的影响都已经在他们跑完的时候就删除了,然后就可以更新答案了

 

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int,int> P;

const int maxn = 2e6+100;
const int maxm = 1e5+10;

char s[maxn];

int a[maxm];
int fa[maxn];
int tot=0;
int num;
int lx[maxn],rx[maxn];
bool vis[maxn];
vector<P> G[maxm];

ll ans[maxm];
ll bit[maxn];

void add_bit(int i,ll x){
    while(i<=num){
        bit[i]+=x;
        i += i&-i;
    }
}

ll sum_bit(int i){
    ll res=0;
    while(i>0){
        res+=bit[i];
        i-= i&-i;
    }
    return res;
}

int Next[maxn][26];
int fail[maxn];
int root;
struct Edge{
    int v,Next;
}edge[maxn];
int tt=0;
int head[maxn];

void add_edge(int u,int v){
    edge[tt].v=v;
    edge[tt].Next=head[u];
    head[u]=tt++;
}

void build(){
    queue<int > Q;
    for(int i=0;i<26;i++){
        if(Next[root][i]){
//            fail[Next[root][i]]=root;
            add_edge(root,Next[root][i]);
            Q.push(Next[root][i]);
        }
    }
    while(!Q.empty()){
        int p=Q.front(); Q.pop();
        for(int i=0;i<26;i++){
            if(Next[p][i]){
                int k;
                for(k=fail[p];k&&!Next[k][i];)k=fail[k];
                fail[Next[p][i]]=Next[k][i];
                add_edge(Next[k][i],Next[p][i]);
                Q.push(Next[p][i]);
            }
        }

    }
}

void dfs(int u){
    lx[u]=++num;
//    vis[u]=true;
    for(int i=head[u];i!=-1;i=edge[i].Next){
        int v=edge[i].v;
        dfs(v);
    }
    rx[u]=num;
}

void dfs_ans(int u){
    add_bit(lx[u],1);
    for(int i=0;i<G[u].size();i++){
        int id=G[u][i].first;
        int v=G[u][i].second;
        ans[id]=sum_bit(rx[v])-sum_bit(lx[v]-1);
    }
    for(int i=0;i<26;i++){
        if(Next[u][i]){
            dfs_ans(Next[u][i]);
        }
    }
    add_bit(lx[u],-1);
}

int main(){
    scanf("%s",s);
    memset(head,-1,sizeof(head));
    int n=0;
    for(int p=0,i=0;s[i];i++){
        if(s[i]=='P'){
            a[++n]=p;
        }
        else if(s[i]=='B'){
            p=fa[p];
        }
        else{
            if(Next[p][s[i]-'a']==0){
                Next[p][s[i]-'a']=++tot;
                fa[Next[p][s[i]-'a']]=p;
                p=Next[p][s[i]-'a'];
            }
            else{
                p=Next[p][s[i]-'a'];
            }
        }
    }
    build();
    dfs(0);
    int m;
    scanf("%d",&m);
    int x,y;
    for(int i=0;i<m;i++){
        scanf("%d%d",&x,&y);
        G[a[y]].push_back(make_pair(i,a[x]));
    }
    dfs_ans(0);
    for(int i=0;i<m;i++){
        printf("%lld\n",ans[i]);
    }
    return 0;
}








 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值