CF1207G Indie Album

CF1207G Indie Album

首先,如果直接暴力存那 (n) 个文本串空间最大 (n^2) 级别显然不行。

我一开始以为是“可持久化AC自动机”,想了好久甚至用LCT去维护。那个翻译写“版本”真是害人不浅qwq

后来发现那就是一颗标准的 (Trie) 树,读入的时候建 (Trie) 即可存下所有的串。

关于查询,在线不是很好搞,那就离线下来,把询问挂到 (Trie) 上。

看看现在需要干什么:求出当前 (Trie) 节点所代表的字符串中 (t) 出现了几次。

这种问题一般都是把询问串建 (ACAM) ,然后跑 (dp) 维护子树和。

动态就是 CF163E e-Government ,搞个树状数组以及 (fail) 树的 (dfs) 序就能做,因为我们只需要知道子树内出现的状态数,所以是一个单点修改区间求和的问题。

那么我们把模式串建 (ACAM) ,跑出 (fail) 树的 (dfs) 序。

在文本串的 (Trie) 上跑 (dfs) ,遍历所有节点回答询问。

考虑在 (dfs) 的时候记录两个值来表示状态:(u1,u2) 分别表示,在文本串 (Trie) 上的节点编号,在询问串上 (Trie) 图的节点编号。

(u1) 沿着文本串 (Trie) 跑,(u2) 沿着询问串 (Trie) 图跑,根据 (u1) 回答询问,根据 (u2) 来在 (fail) 树上修改。

对于每一个 (dfs) 状态, (u2) 所在的节点就是 (u1) 代表的文本串 (Trie) 上前缀的状态,相当于跑单个文本串。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef double db;
#define x first
#define y second
#define sz(v) (int)v.size()
#define pb(x) push_back(x)
#define mkp(x,y) make_pair(x,y)
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=0;c=getchar();}
	while(isdigit(c))x=x*10+c-'0',c=getchar();
	return f?x:-x;
}
int rdc(){
	char ch=getchar();
	while(!isalpha(ch))ch=getchar();
	return ch-'a';
}
#define N 400005
int n,m,ch[N][26],ed[N],to[N],ln[N],rn[N],tmr,tr[N],tot,ans[N],fail[N],trie[N][26],cnt;
vector<int>e[N],q[N];
void insert(char*str,int id){
	int u=0;
	for(int i=0,len=strlen(str);i<len;++i){
		int c=str[i]-'a';
		if(!ch[u][c])ch[u][c]=++cnt;
		u=ch[u][c];
	}
	ed[id]=u;
}
void build_fail(){
	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)e[fail[i]].pb(i);
}
void dfs1(int u){
	ln[u]=++tmr;
	for(int v:e[u])dfs1(v);
	rn[u]=tmr;
}
void add(int x,int d){if(!x)return;for(int i=x;i<=tmr;i+=i&-i)tr[i]+=d;}
int ask(int x){int res=0;for(int i=x;i>0;i-=i&-i)res+=tr[i];return res;}
void dfs2(int u1,int u2){
	add(ln[u2],1);
	for(int i:q[u1])ans[i]=ask(rn[ed[i]])-ask(ln[ed[i]]-1);
	for(int i=0;i<26;++i)if(trie[u1][i])dfs2(trie[u1][i],ch[u2][i]);
	add(ln[u2],-1);
}
signed main(){
	n=read();
	for(int i=1;i<=n;++i){
		int op=read(),pre=0,x;
		if(op==2)pre=read();
		x=rdc();
		if(!trie[to[pre]][x])trie[to[pre]][x]=++tot;
		to[i]=trie[to[pre]][x];
	}
	m=read();
	for(int i=1;i<=m;++i){
		int x=read();static char str[N];
		scanf("%s",str);
		insert(str,i),q[to[x]].pb(i);
	}
	build_fail(),dfs1(0),dfs2(0,0);
	for(int i=1;i<=m;++i)printf("%d
",ans[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/zzctommy/p/13889472.html