Luogu2414 [NOI2011]阿狸的打字机

先建AC自动机,然后建next树,然后把每个询问加进AC自动机上,dfs一遍,把当前insta的节点加进树状数组,如果碰到询问就在树状数组上查询区间和,回溯时再把节点从树状数组中删去

#include<bits/stdc++.h>
#define maxn 100005
using namespace std;

struct node{
	int lc[26],next,pre;
	vector<int> query;
}AC[maxn],trie[maxn];

char s[maxn];
int c[maxn];
int m,len,tot,match[maxn],siz[maxn],n;
int edge[maxn],head[maxn],nextt[maxn];
int a[maxn],b[maxn],ans[maxn],num[maxn];
queue<int> q;

void aadd(int x,int k){
	for(;x<=tot;x+=(x&-x)) c[x]+=k;
}

int ask(int x){
	int sum=0;
	for(;x;x-=(x&-x)) sum+=c[x];
	return sum;
}

void add(int x,int y,int tot){
	edge[tot]=y;nextt[tot]=head[x];head[x]=tot;
}

void build_trie(){
	int root=0;
	for(int i=1;i<=len;i++){
		if('a'<=s[i]&&s[i]<='z'){
			if(!AC[root].lc[s[i]-'a']) AC[root].lc[s[i]-'a']=++tot,AC[AC[root].lc[s[i]-'a']].pre=root;
			root=AC[root].lc[s[i]-'a'];
		}
		if(s[i]=='B') root=AC[root].pre;
		if(s[i]=='P') match[++n]=root;
	}
}

void build_AC(){
	for(int i=0;i<26;i++) if(AC[0].lc[i]) q.push(AC[0].lc[i]);
	while(!q.empty()){
		int x=q.front();
		q.pop();
		for(int i=0;i<26;i++){
			if(AC[x].lc[i]) AC[AC[x].lc[i]].next=AC[AC[x].next].lc[i],q.push(AC[x].lc[i]);
			else AC[x].lc[i]=AC[AC[x].next].lc[i];
		}
	}
}

void dfs(int x){
	if(x) aadd(num[x],1);
	for(int i=0;i<AC[x].query.size();i++){
		int t=AC[x].query[i];
		ans[t]=ask(num[match[a[t]]]+siz[match[a[t]]]-1)-ask(num[match[a[t]]]-1);
	}
	for(int i=0;i<26;i++)
		if(trie[x].lc[i])
			dfs(trie[x].lc[i]);
	if(x) aadd(num[x],-1);
}

void dfs1(int x){
	siz[x]=1;
	num[x]=++tot;
	for(int i=head[x];i;i=nextt[i]){
		int y=edge[i];
		dfs1(y);
		siz[x]+=siz[y];
	}
}

int main(){
	scanf("%s",s+1);
	len=strlen(s+1);
	build_trie();
	for(int i=0;i<=tot;i++) trie[i]=AC[i];
	build_AC();
	for(int i=1;i<=tot;i++) add(AC[i].next,i,i);
	tot=0;
	dfs1(0);
	scanf("%d",&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&a[i],&b[i]);
		AC[match[b[i]]].query.push_back(i);
	}
	dfs(0);
	for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
	return 0;
}
posted @ 2019-09-29 18:39  ElevenX  阅读(110)  评论(0编辑  收藏  举报