• 【刷题】BZOJ 2434 [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

    HINT

    1<=N<=10^5

    1<=M<=10^5

    输入总长<=10^5

    Solution

    AC自动机
    不知道性质完全做不了

    如果AC自动机中的两个串 (p)(s) ,满足 (p)(s) 中出现了 (k) 次,那么 (k) 等于 (p) 串结束点在fail树上的子树中有多少个节点属于串 (s)

    维护树中一个节点的子树和,就随便搞了,我用的BIT
    然后就可以离线了
    首先把串按照题目含义建出AC自动机
    然后getfail
    对询问排序
    开始算答案,重新跟着给的串走一遍,达到一个点,把它的贡献加入BIT,离开一个点则减去,那么BIT中保存的就一定是当前达到的点到根路径上的点的贡献
    (注意,加贡献一定是加在这个点在fail树中的位置,而不是AC自动机上的位置)
    所以如果当前到达了一个询问,就可以直接在BIT查答案了

    #include<bits/stdc++.h>
    #define ui unsigned int
    #define ll long long
    #define db double
    #define ld long double
    #define ull unsigned long long
    const int MAXN=100000+10,MAXM=100000+10;
    int ch[MAXN][30],fail[MAXN],n,m,cnt,st[MAXN],e,beg[MAXN],nex[MAXN<<1],to[MAXN<<1],nt,ans[MAXN],ed[MAXN],fa[MAXN],fl[MAXN],ps[MAXN];
    char s[MAXN];
    std::queue<int> q;
    struct node{
    	int x,y,id;
    	inline bool operator < (const node &A) const {
    		return y<A.y;
    	};
    };
    node qs[MAXM];
    struct BIT{
    	int C[MAXN];
    	inline int lowbit(int x)
    	{
    		return x&(-x);
    	}
    	inline void add(int x,int k)
    	{
    		while(x<=nt)C[x]+=k,x+=lowbit(x);
    	}
    	inline int sum(int x)
    	{
    		int res=0;
    		while(x>0)res+=C[x],x-=lowbit(x);
    		return res;
    	}
    };
    BIT T;
    template<typename T> inline void read(T &x)
    {
    	T data=0,w=1;
    	char ch=0;
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    	x=data*w;
    }
    template<typename T> inline void write(T x,char ch='')
    {
    	if(x<0)putchar('-'),x=-x;
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    	if(ch!='')putchar(ch);
    }
    template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
    template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
    template<typename T> inline T min(T x,T y){return x<y?x:y;}
    template<typename T> inline T max(T x,T y){return x>y?x:y;}
    inline void insert(int x,int y)
    {
    	to[++e]=y;
    	nex[e]=beg[x];
    	beg[x]=e;
    }
    inline void init()
    {
    	int x=0;
    	for(register int i=0,lt=strlen(s);i<lt;++i)
    		if(s[i]=='P')fl[x]=++n,ps[n]=x;
    		else if(s[i]=='B')x=fa[x];
    		else if(!ch[x][s[i]-'a'+1])fa[cnt+1]=x,x=ch[x][s[i]-'a'+1]=++cnt;
    		else x=ch[x][s[i]-'a'+1];
    }
    inline void getfail()
    {
    	for(register int i=1;i<=26;++i)
    		if(ch[0][i])q.push(ch[0][i]);
    	while(!q.empty())
    	{
    		int x=q.front();
    		q.pop();
    		for(register int i=1,y,z;i<=26;++i)
    			if(ch[x][i])
    			{
    				y=ch[x][i],z=fail[x];
    				while(z&&!ch[z][i])z=fail[z];
    				fail[y]=ch[z][i];
    				q.push(y);
    			}
    	}
    }
    inline void dfs(int x,int f)
    {
    	st[x]=++nt;
    	for(register int i=beg[x];i;i=nex[i])
    		if(to[i]==f)continue;
    		else dfs(to[i],x);
    	ed[x]=nt;
    }
    inline void solve()
    {
    	int x=0,nq=1;
    	for(register int i=0,lt=strlen(s);i<lt;++i)
    	{
    		if(s[i]=='P')
    			while(fl[x]==qs[nq].y)ans[qs[nq].id]=T.sum(ed[ps[qs[nq].x]])-T.sum(st[ps[qs[nq].x]]-1),++nq;
    		else if(s[i]=='B')T.add(st[x],-1),x=fa[x];
    		else x=ch[x][s[i]-'a'+1],T.add(st[x],1);
    	}
    }
    int main()
    {
    	scanf("%s",s);
    	init();getfail();
    	for(register int i=1;i<=cnt;++i)insert(i,fail[i]),insert(fail[i],i);
    	read(m);
    	for(register int i=1;i<=m;++i)read(qs[i].x),read(qs[i].y),qs[i].id=i;
    	dfs(0,-1);
    	std::sort(qs+1,qs+m+1);
    	solve();
    	for(register int i=1;i<=m;++i)write(ans[i],'
    ');
    	return 0;
    }
    
  • 相关阅读:
    STOAdiary20110312抉择
    STOA静夜思
    STOAOO
    STOAdiary20110316翻译的一天
    STOAdiary20110318疲倦与激情
    STOAdiary20110314平静的一天
    Silverlight入门
    Postgres远程访问配置
    [收藏]Jquery客户端拖拽排序方法
    整理的邮件一个邮件发送类
  • 原文地址:https://www.cnblogs.com/hongyj/p/9301947.html
Copyright © 2020-2023  润新知