codeforces 1207G

题目链接

题意

有n个字符串,给出方式:
第i行输入操作序号,如果是1,后面接一个字符,说明这个字符串只有一个字符
如果是2,后面接一个编号j ( j < i ) (j<i) ,和一个字符,说明第i个字符串是在第j个字符串后面拼上一个字符,形成的。
然后有m次询问,每次给出一个字符串s和一个整数i,求在第i个字符串里字符串s出现了几次

数据范围

所有整数小于等于4e5,询问字符串总长小于等于4e5

解法

这个题目首先是将询问串建AC自动机,然后在原串形成的树(可以观察原来的字符串形成了一些树状结构)上跑,查询答案的时候相当于询问某个字符串在AC自动机上出现了几次,这里正确的原因是因为我们在原串形成的树上dfs的时候,其实就维护了当前这条链的AC自动机的信息。这里需要将AC自动机进行子树加操作,使用欧拉序就可以维护了。

#include<bits/stdc++.h>
using namespace std;
const int maxn=4e5+5;
inline int read(){
	char c=getchar();int t=0,f=1;
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
	return t*f;
}
int n,m;
typedef pair<int,int> pii;
vector<pii> son[maxn],q[maxn];
char c[maxn],s[5];
int ch[maxn][26],val[maxn],fail[maxn],cnt;
inline int add(){
	int now=0,l=strlen(c);
	for(int i=0;i<l;i++){
		if(!ch[now][c[i]-'a'])ch[now][c[i]-'a']=++cnt;
		now=ch[now][c[i]-'a'];
	}
	return now;
}
vector<int> F[maxn];
void build(){
	queue<int> q;
	for(int i=0;i<26;i++)if(ch[0][i])q.push(ch[0][i]);
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=0;i<26;i++){
			if(ch[u][i]){
				fail[ch[u][i]]=ch[fail[u]][i];
				q.push(ch[u][i]);
			}
			else{ch[u][i]=ch[fail[u]][i];}
		}
	}
	for(int i=1;i<=cnt;i++)F[fail[i]].push_back(i);
}
int dfn,din[maxn],dout[maxn],ans[maxn];
void dfs(int u){
	din[u]=++dfn;
	for(int i=0;i<F[u].size();i++){
		int v=F[u][i];
		dfs(v);
	}
	dout[u]=dfn;
}
int tr[maxn*5];
inline int lowbit(int x){return x&(-x);}
inline void modify(int x,int val){
	while(x<=dfn){tr[x]+=val;x+=lowbit(x);}
}
inline int query(int x){
	int ans=0;
	while(x){ans+=tr[x];x-=lowbit(x);}
	return ans;
}
void dfs2(int u,int now){
	modify(din[u],1);
	for(int i=0;i<q[now].size();i++){
		pii t=q[now][i];
		ans[t.second]=query(dout[t.first])-query(din[t.first]-1);
	}
	for(int i=0;i<son[now].size();i++){
		pii t=son[now][i];
		dfs2(ch[u][t.first],t.second);
	}
	modify(din[u],-1);
}
int main(){
	n=read();
	for(int i=1;i<=n;i++){
		int op=read();int fa=0;
		if(op==1);
		else{fa=read();}
		scanf("%s",s);
		son[fa].push_back(pii(s[0]-'a',i));
	}
	m=read();
	for(int i=1;i<=m;i++){
		int d;
		scanf("%d%s",&d,c);
		q[d].push_back(pii(add(),i));
	}
	build();
	dfs(0);
	dfs2(0,0);
	for(int i=1;i<=m;i++){
		printf("%d\n",ans[i]);
	}
	return 0;
}

发布了62 篇原创文章 · 获赞 1 · 访问量 997

猜你喜欢

转载自blog.csdn.net/wmhtxdy/article/details/103826259
今日推荐