51nod 麦克打电话(AC自动机+树状数组)

SAM+线段树合并的裸题。
但我们讨论AC自动机的做法。
先建出AC自动机。考虑询问在[a,b]中出现的次数就是\([1,b]\)的出现次数-\([1,a-1]\)的出现次数。把询问离线。然后我们要求的就是第i个字符串在\([1,x]\)中出现次数。我们在从\([1,x-1]\)\([1,x]\)的过程中把\(S_x\)放到AC自动机上跑,跑到的每一个节点都加1。然后询问就是在\(S_i\)在fail树上对应位置求一个子树和这个用树状数组维护就行。因为fail树上每一个节点的后代都包含这个节点。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int N=301000;
int n,m,ans[501000];
string s[N];
int cnt,head[N];
struct edge{
	int to,nxt;
}e[N];
void add(int u,int v){
	cnt++;
	e[cnt].nxt=head[u];
	e[cnt].to=v;
	head[u]=cnt;
}
struct ques{
	int x,k,id;
	ques(int xx=0,int kk=0,int idx=0){
		x=xx;k=kk;id=idx;
	}
};
vector<ques> vec[N];
struct Tree{
	int dep[N],size[N],dfn[N],tot;
	int tr[N];
	void dfs(int u,int f){
		dep[u]=dep[f]+1;
		dfn[u]=++tot;
		size[u]=1;
		int maxson=-1;
		for(int i=head[u];i;i=e[i].nxt){
			int v=e[i].to;
			dfs(v,u);
			size[u]+=size[v];
		}
	}
	int lowbit(int x){
		return x&-x;
	}
	void add(int x){
		for(int i=x;i<=tot;i+=lowbit(i))tr[i]++;
	}
	int getsum(int x){
		int tmp=0;
		for(int i=x;i;i-=lowbit(i))tmp+=tr[i];
		return tmp;
	}
}tree;
bool cmp(int x,int y){
	if(tree.dfn[x]<tree.dfn[y])return true;
	else return false;
}
struct AC{
	int trans[N][27],point[N],tot,fail[N];
	void ins(string s,int k){
		int now=0;
		int len=s.size();
		for(int i=0;i<len;++i){
			if(trans[now][s[i]-'a'+1]==0)trans[now][s[i]-'a'+1]=++tot;
			now=trans[now][s[i]-'a'+1];
		}
		point[k]=now;
	}
	void get_fail(){
		queue<int> q;
		for(int i=1;i<=26;++i)if(trans[0][i])q.push(trans[0][i]);
		while(!q.empty()){
			int now=q.front();
			q.pop();
			for(int i=1;i<=26;++i)
				if(trans[now][i])fail[trans[now][i]]=trans[fail[now]][i],q.push(trans[now][i]);
				else trans[now][i]=trans[fail[now]][i];
		}
	}
	void work(string s){
		int now=0;
		int len=s.size();;
		tree.add(tree.dfn[0]);
		for(int i=0;i<len;++i){
			now=trans[now][s[i]-'a'+1];
			tree.add(tree.dfn[now]);
		}
	}
}ac;
int read(){
	int sum=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
	return sum*f;
}
int main(){
	n=read();m=read();
	for(int i=1;i<=n;++i)cin>>s[i],ac.ins(s[i],i);
	int a,b,c;
	for(int i=1;i<=m;++i){
		a=read();b=read();c=read();
		vec[a-1].push_back(ques(ac.point[c],-1,i));
		vec[b].push_back(ques(ac.point[c],1,i));
	}
	ac.get_fail();
	for(int i=1;i<=ac.tot;++i)add(ac.fail[i],i);
	tree.dfs(0,0);
	for(int i=1;i<=n;++i){
		ac.work(s[i]);
		for(int j=0;j<vec[i].size();++j){
			int L=tree.dfn[vec[i][j].x];
			int R=tree.dfn[vec[i][j].x]+tree.size[vec[i][j].x]-1;
			ans[vec[i][j].id]+=vec[i][j].k*(tree.getsum(R)-tree.getsum(L-1));
		}
	}
	for(int i=1;i<=m;++i)printf("%d\n",ans[i]);
	return 0;
}
posted @ 2019-01-07 21:22  Xu-daxia  阅读(191)  评论(0编辑  收藏  举报