codeforces 1207G

トピックリンク

問題の意味

:によって与えられるn個の文字列
が文字列に1つの文字であることを示す文字、続いて、1であれば、i番目の行番号入力操作
番号jが続くが2である場合、 J < (J <I) 、および形成呪文を、以下のi、j番目の文字列で記述された文字列。
そこは、その後たびに、与えられた文字列と整数のI、Sは、いくつかの中で発生したリクエスト文字列のi番目の文字列をm回を頼まれます

データ範囲

全ての整数以下で4E5、文字列クエリの全長未満4E5

ソリューション

AC自動機に対応する文字列に尋ねられたときに最初のトピックは、実行、クエリの答えに(元の文字列は、ツリー構造の数の形成を観察することができます)ツリーの元の形式でクエリ文字列AC自動機、およびその文字列を構築することです右の理由のために、ここで、いくつかありました実際には、ACオートマトンのこのチェーンの現在の情報を保持したときに、私たちは木DFS元の文字列の形式であるためです。これはオイラーの順序を維持することができる、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