BZOJ2434 [Noi2011]阿狸的打字机【AC自动机+dfs序+树状数组】

题意:给出阿狸的打字顺序(小写字母是写入,‘B'是删除,’P'是打印,此处产生新的字符串),给出多组询问,每次询问第x号字符串在第y号字符串中的出现次数。

学过AC自动机的都知道,自动机上串A在串B中的出现次数,就是fail树上以串A结尾节点为根的子树中,串B的节点个数。这题我们用离线的方法,以y为关键字排序,在fail树的dfs序上用树状数组维护节点个数。为什么要按y为关键字排序呢?忽略‘P'操作,你没发现它打印删除打印删除的,挺像树的入栈出栈序的么。。。然后按y排序,后面的串上节点个数,就是入栈出栈序的前缀和啊0.0。(怎么觉得描述出来乱乱的,不好意思,词穷词穷= =。)

算法流程:

1.根据输入建立AC自动机,把fail树搞出来。

2.将询问以y为关键字排序。

3.扫一遍输入的串,如果是小写字母,就在树状数组中把该点位置+1,如果是‘B',就把它删除的对应节点在树状数组中-1,如果是’P',在树状数组中截取x的一段区间即是答案。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<bitset>
#include<queue>
#include<vector>
#define ll long long
#define N 100010
#define INF 0x3f3f3f3f
using namespace std;
char str[N];
int m;
int tr[N][30],g[N],id,pnt[N],len;
int end[N],begin[N],in[N],out[N],_index=0;
vector<int> e[N];
int ans[N],r[N];
queue<int> q;
struct node{
	int a,b;
	int id;
	node(){}
	node(int x,int y){a=x;b=y;}
	friend bool operator < (node x,node y){
		return x.b==y.b ? x.a<y.a : x.b<y.b;
	}
}que[N];
void build(){
	pnt[1]=0;
	int x=1;
	for(int i=0;i<len;i++){
		if(str[i]=='B'){
			x=pnt[x];
		}
		else if(str[i]=='P'){
			id++;
			end[id]=x;
		}
		else{
			if(!tr[x][str[i]-'a']) {
				tr[x][str[i]-'a']=i+2; 
				pnt[i+2]=x;
			}
			x=tr[x][str[i]-'a'];
		}
	}
}
void init(){
	gets(str);
	len=strlen(str);
	build();
	scanf("%d",&m);
	for(int i=1;i<=m;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		que[i].a=end[x];
		que[i].b=end[y];
		que[i].id=i;
	}
}
void bfs(){
	int j,y;
	g[1]=0;
	q.push(1);
	while(q.size()){
		int x=q.front();
		q.pop();
		for(int i=0;i<26;i++){
			if(y=tr[x][i]){
				for(j=g[x];j;j=g[j]) if(tr[j][i]) break;
				if(j){
					g[y]=tr[j][i];
					e[tr[j][i]].push_back(y);
				}
				else{
					g[y]=1;
					e[1].push_back(y);
				}
				q.push(y);
			}
		}
	}
}
void dfs(int u){
	in[u]=++_index;
	for(int i=0;i<e[u].size();i++) dfs(e[u][i]);
	out[u]=++_index;
}
namespace BIT{
	int c[N*2];
	int lowbit(int x){ return x&(-x); }
	void add(int x,int ad){
		while(x<=_index){
			c[x]+=ad;
			x+=lowbit(x);
		}
	}
	int sum(int x){
		int res=0;
		while(x){
			res+=c[x];
			x-=lowbit(x);
		}
		return res;
	}
}
void print(){
	int i,j=1,now=0;
	sort(que+1,que+m+1);
	for(i=0;i<len;i++){
		if(str[i]=='B'){
			BIT::add(in[now+2],-1);
			now=pnt[now+2]-2;
		}
		else if(str[i]=='P');
		else{
			now=i;
			BIT::add(in[now+2],1);
		}
		while(que[j].b-2==i) {
			ans[que[j].id]=BIT::sum(out[que[j].a])-BIT::sum(in[que[j].a]-1);
			j++;
		}
	}
	for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
}
int main(){
	init();
	bfs();
	dfs(1);
	print();
	return 0;
}


猜你喜欢

转载自blog.csdn.net/u011431896/article/details/45242777