zoukankan      html  css  js  c++  java
  • [NOI2011]阿狸的打字机

    [NOI2011]阿狸的打字机

    题目大意:

    一个老式的打字机按照如下的方式工作:用一个栈存储想要打印的内容(小写英文字母),B键将栈顶字母出栈,P键将栈中所有字母打印出来。

    给定长度为(n(nle10^5))的操作序列(包含(26)个小写字母和操作BP)。(m(mle10^5))次询问,第(x)个打印出来的字符串在第(y)个打印出来的字符串中出现了几次。

    思路:

    该打字机的特性使得我们可以很容易地构造出一个AC自动机,插入小写字母同普通的AC自动机,B操作时直接将返回到当前结点在Trie上的父亲即可。

    将原问题放到Fail树上,就是(x)对应的子树中有多少个结点对应着(y)。求出Fail树的DFS序,树状数组维护即可。

    源代码:

    #include<queue>
    #include<cstdio>
    #include<cctype>
    #include<vector>
    #include<algorithm>
    inline int getint() {
    	register char ch;
    	while(!isdigit(ch=getchar()));
    	register int x=ch^'0';
    	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    	return x;
    }
    const int N=1e5+1,M=1e5;
    char s[N];
    int m,par[N],pos[N],in[N],out[N],cnt,ans[M];
    std::vector<int> e[N];
    inline void add_edge(const int &u,const int &v) {
    	e[u].push_back(v);
    	par[v]=u;
    }
    struct Query {
    	int x,y,id;
    	bool operator < (const Query &rhs) const {
    		return y<rhs.y;
    	}
    };
    Query q[M];
    class FenwickTree {
    	private:
    		int val[N+1];
    		int lowbit(const int &x) const {
    			return x&-x;
    		}
    	public:
    		void modify(int p,const int &x) {
    			for(;p<=cnt;p+=lowbit(p)) val[p]+=x;
    		}
    		int query(int p) const {
    			int ret=0;
    			for(;p;p-=lowbit(p)) ret+=val[p];
    			return ret;
    		}
    };
    FenwickTree t;
    class AhoCorasick {
    	private:
    		int ch[N][26],last[N],fail[N];
    		int sz,new_node() {
    			return ++sz;
    		}
    		int idx(const char &c) const {
    			return c-'a';
    		}
    	public:
    		void insert(const char s[]) {
    			for(register int i=0,p=0;s[i];i++) {
    				if(s[i]=='P') {
    					pos[++pos[0]]=p;
    					continue;
    				}
    				if(s[i]=='B') {
    					p=last[p];
    					continue;
    				}
    				const int c=idx(s[i]);
    				if(!ch[p][c]) {
    					ch[p][c]=new_node();
    					last[ch[p][c]]=p;
    				}
    				p=ch[p][c];
    			}
    		}
    		void get_fail() {
    			std::queue<int> q;
    			for(register int i=0;i<26;i++) {
    				if(ch[0][i]) q.push(ch[0][i]);
    			}
    			while(!q.empty()) {
    				const int &x=q.front();
    				for(register int i=0;i<26;i++) {
    					int &y=ch[x][i];
    					if(y) q.push(y);
    					(y?fail[y]:y)=ch[fail[x]][i];
    				}
    				add_edge(fail[x],x);
    				q.pop();
    			}
    		}
    		void solve() const {
    			for(register int i=0,j=0,k=0,p=0;s[i];i++) {
    				if(s[i]=='P') {
    					if(++k==q[j].y) {
    						for(;j<m&&q[j].y==k;j++) {
    							ans[q[j].id]=t.query(out[pos[q[j].x]])-t.query(in[pos[q[j].x]]-1);
    						}
    					}
    					continue;
    				}
    				if(s[i]=='B') {
    					t.modify(in[p],-1);
    					p=last[p];
    					continue;
    				}
    				p=ch[p][idx(s[i])];
    				t.modify(in[p],1);
    			}
    		}
    };
    AhoCorasick ac;
    void dfs(const int &x) {
    	in[x]=++cnt;
    	for(unsigned i=0;i<e[x].size();i++) {
    		const int &y=e[x][i];
    		dfs(y);
    	}
    	out[x]=cnt;
    }
    int main() {
    	scanf("%s",s);
    	ac.insert(s);
    	ac.get_fail();
    	dfs(0);
    	m=getint();
    	for(register int i=0;i<m;i++) {
    		q[i].x=getint();
    		q[i].y=getint();
    		q[i].id=i;
    	}
    	std::sort(&q[0],&q[m]);
    	ac.solve();
    	for(register int i=0;i<m;i++) {
    		printf("%d
    ",ans[i]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    关于面向对象
    关于内存的划分和传引用传参数的区别
    关于目前我们专业的各种发展方向
    关于C语言底层
    关于游戏行业目前的形势
    关于jsp,javascript,php等语言
    鼠标滑动图片变大
    在Linux环境下mysql的root密码忘记解决方法
    百度网盘
    bootsrtap 主题元素
  • 原文地址:https://www.cnblogs.com/skylee03/p/9445226.html
Copyright © 2011-2022 走看看