Codeforces 547E. Mike and Friends 题解

题目大意:

  • 给定\(n\)个字符串\(s_1,s_2,\dots,s_n\)
  • \(q\)次询问\(s_k\)\(s_{l,\dots,r}\)中出现了多少次。

题目链接:547E. Mike and Friends


题解:考虑 AC 自动机的 fail 树,将每一个串插入到 AC 自动机中,然后建出 fail 树,一个串出现的次数就是它的 fail 树的子树大小,因为这一道题不是全局查询,所以讲每一个询问差分成\(l-1,r\)两个询问,排序,每一次对于当前串的链全部加一,然后直接统计即可。

查询子树和用 dfs 序加上树状数组即可。

代码:

#include <queue>
#include <cstdio>
using namespace std;
int abs(int a){
	return a<0?-a:a;
}
const int Maxn=200000;
const int Maxq=500000;
int n,q;
char s[Maxn+5];
int pos[Maxn+5];
int dfn[Maxn+5],dfn_tot;
vector<int> edge[Maxn+5];
int sz[Maxn+5];
int k[Maxq+5];
struct Node{
	int ch[26];
	int fail,fa;
}node[Maxn+5];
vector<int> que[Maxn+5];
int id_tot=1;
int insert(int n){
	int root=1;
	for(int i=1;i<=n;i++){
		if(node[root].ch[s[i]-'a']==0){
			node[root].ch[s[i]-'a']=++id_tot;
			node[id_tot].fa=root;
		}
		root=node[root].ch[s[i]-'a'];
	}
	return root;
}
void dfs(int u){
	dfn[u]=++dfn_tot;
	sz[u]=1;
	for(int i=0;i<(int)edge[u].size();i++){
		int v=edge[u][i];
		dfs(v);
		sz[u]+=sz[v];
	}
}
void build(){
	queue<int> q;
	for(int i=0;i<26;i++){
		if(node[1].ch[i]){
			node[node[1].ch[i]].fail=1;
			q.push(node[1].ch[i]);
		}
		else{
			node[1].ch[i]=1;
		}
	}
	while(!q.empty()){
		int u=q.front();
		q.pop();
		for(int i=0;i<26;i++){
			if(node[u].ch[i]){
				node[node[u].ch[i]].fail=node[node[u].fail].ch[i];
				q.push(node[u].ch[i]);
			}
			else{
				node[u].ch[i]=node[node[u].fail].ch[i];
			}
		}
	}
	for(int i=2;i<=id_tot;i++){
		edge[node[i].fail].push_back(i);
	}
	dfs(1);
}
int f[Maxn+5];
void add(int x,int a){
	for(int i=x;i<=id_tot;i+=(i&(-i))){
		f[i]+=a;
	}
}
int query(int x){
	int ans=0;
	for(int i=x;i>0;i-=(i&(-i))){
		ans+=f[i];
	}
	return ans;
}
int ans[Maxq+5];
int main(){
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++){
		scanf("%s",s+1);
		int len=0;
		while(s[++len]!='\0');
		len--;
		pos[i]=insert(len);
	}
	build();
	for(int i=1;i<=q;i++){
		int l,r;
		scanf("%d%d%d",&l,&r,&k[i]);
		if(l>1){
			que[l-1].push_back(-i);
		}
		que[r].push_back(i);
	}
	for(int i=1;i<=n;i++){
		int root=pos[i];
		while(root!=1){
			add(dfn[root],1);
			root=node[root].fa;
		}
		for(int j=0;j<(int)que[i].size();j++){
			int id=abs(que[i][j]);
			int x=pos[k[id]];
			if(que[i][j]>0){
				ans[id]+=query(dfn[x]+sz[x]-1)-query(dfn[x]-1);
			}
			else{
				ans[id]-=query(dfn[x]+sz[x]-1)-query(dfn[x]-1);
			}
		}
	}
	for(int i=1;i<=q;i++){
		printf("%d\n",ans[i]);
	}
	return 0;
}
posted @ 2020-07-26 17:27  with_hope  阅读(288)  评论(0编辑  收藏  举报