[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;
}
原文地址:https://www.cnblogs.com/skylee03/p/9445226.html