• [BZOJ2434] [NOI2011]阿狸的打字机


    Description

    阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。打字机上只有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个询问的答案。

    Sample Input

    aPaPBbP 
    3
    1 2
    1 3
    2 3
    

    Sample Output

    2
    1
    0
    

    Solution

    考虑一个暴力,我们想求的是第(x)个串在第(y)个串出现了多少次,那么我们先建出(AC)自动机,枚举第(y)个串的每一个位置,沿着(fail)指针往上跳,如果能正好跳到第(x)个串的末尾,那么就算一次。

    那么考虑怎么优化这个过程,我们把(fail)指针反过来,建出(fail)树,那么问题就变成了(x)子树内有多少个属于(y)的点。

    所以离线之后直接用树状数组维护子树信息即可。

    #include<bits/stdc++.h>
    using namespace std;
     
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
     
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    const int maxn = 2e5+10;
    
    char s[maxn];
    int sta[maxn],top,cnt;
    int tr[maxn][26],fail[maxn];
    
    void make_fail() {
    	queue<int > q;
    	for(int i=0;i<26;i++) if(tr[0][i]) q.push(tr[0][i]);
    	while(!q.empty()) {
    		int x=q.front();q.pop();
    		for(int i=0;i<26;i++)
    			if(tr[x][i]) fail[tr[x][i]]=tr[fail[x]][i],q.push(tr[x][i]);
    			else tr[x][i]=tr[fail[x]][i];
    	}
    }
    
    int head[maxn],tot,dfn[maxn],rev[maxn],dfn_cnt,sz[maxn];
    struct edge{int to,nxt;}e[maxn<<1];
    
    void add(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
    void ins(int u,int v) {add(u,v),add(v,u);}
    
    void dfs(int x,int fa) {
    	dfn[x]=++dfn_cnt;sz[x]=1;
    	for(int i=head[x];i;i=e[i].nxt)
    		if(e[i].to!=fa) dfs(e[i].to,x),sz[x]+=sz[e[i].to];
    }
    
    struct Binary_Indexed_Tree {
    	int t[maxn];
    	void modify(int x,int v) {for(;x<=cnt+1;x+=x&-x) t[x]+=v;}
    	int query(int x,int ans=0) {for(;x;x-=x&-x) ans+=t[x];return ans;}
    }BIT;
    
    #define pii pair<int,int >
    #define vec vector<pii >
    
    vec res[maxn];
    int ans[maxn],n,m,pos[maxn];
    
    void build() {
    	scanf("%s",s+1);n=strlen(s+1);
    	int pt=0;
    	for(int i=1;i<=n;i++) {
    		if(s[i]=='B') top--;
    		else if(s[i]=='P') pos[++pt]=sta[top];
    		else {
    			int &v=tr[sta[top]][s[i]-'a'];
    			if(!v) v=++cnt;
    			sta[++top]=v;
    		}
    	}
    	make_fail();
    	for(int i=1;i<=cnt;i++) ins(i,fail[i]);
    	dfs(0,-1);
    }
    
    void solve() {
    	top=0;
    	int pt=0;read(m);
    	for(int i=1,x,y;i<=m;i++) read(x),read(y),res[y].push_back(make_pair(x,i));
    	for(int i=1;i<=n;i++) {
    		if(s[i]=='B') BIT.modify(dfn[sta[top]],-1),top--;
    		else if(s[i]=='P') {
    			for(vec :: iterator j=res[++pt].begin();j!=res[pt].end();j++) {
    				int x=pos[(*j).first],id=(*j).second;
    				ans[id]=BIT.query(dfn[x]+sz[x]-1)-BIT.query(dfn[x]-1);
    			}
    		} else {
    			int v=tr[sta[top]][s[i]-'a'];
    			sta[++top]=v;BIT.modify(dfn[v],1);
    		}
    	}
    	for(int i=1;i<=m;i++) write(ans[i]);
    }
    
    int main() {
    	build();solve();
    	return 0;
    }
    
  • 相关阅读:
    oc基础第二天类与对象---1复习代码
    oc基础第二天类与对象---1复习
    oc基础第一天---类的方法,类与对象
    oc基础第一天---类与对象
    oc基础第一天---面向过程与面向对象
    oc基础第一天---c语言和oc语言的对比
    oc基础第一天---c语言与oc语言对比
    第一阶段c语言结晶说明
    mvc 使用json.net 替换JsonResult 默认序列化
    Mvc ModelBinder 一对多自定义数据格式 post提交
  • 原文地址:https://www.cnblogs.com/hbyer/p/10531499.html
Copyright © 2020-2023  润新知