……我……嗯……建trie写成了n^2,T了一年
然后奇技淫巧艹到rank1了……坐等被yigezhongxuesheng大爷艹回来233333
这题……本来觉得后面那一堆会调一年,然而万万没想到是跪在了建trie上
询问x串在y串中出现过多少次,等价于查询在【以AC自动机的根节点为根】的fail树上,x串终止节点的子树中出现过多少个y串中字符对应的节点
于是用树状数组维护fail树的DFS序,遍历trie树(也就是给出的字符串),并将当前在stack中的节点的值++,当访问到终止态的时候,查询当前终止态代表的字符串上挂的询问,直接用树状数组求个区间和就好
代码………………我觉得不能看2333333
flaze先去写一波备注哼
…………
#include<bits/stdc++.h>
#define MAXN 200005
using namespace std; int n;
int N;
//=========================================================
//=====FIO=======FTC大爷的读入输出优化====
struct buf{
char z[1<<25],*s;
char e[1<<25],*t;
char f[24];
buf():s(z),t(e){
fread(z,1,sizeof z,stdin);
}
~buf(){
fwrite(e,1,t-e,stdout);
}
void read_str(char* v){
while(*s<48)++s;
while(*s>32)*v++=*s++;
*v=0;
}
char* str(){
while(*s<48)++s;
char* v=s;
while(*s>32)++s;
*s=0;
return v;
}
void out(const char* v){
while(*v)*t++=*v++;
*t++=10;
}
operator int(){
int v=0,j=0;
while(*s<48)j=*s++;
while(*s>32)
v=v*10+*s++-48;
return j^45?v:-v;
}
void out(int v){
char* l=f;
if(!v)*t++=48;
else{
if(v<0){*t++=45;
v*=-1;}
for(;v;v/=10)
*l++=v%10+48;
while(l-f)
*t++=*--l;
}
*t++=10;
}
}it;
//==========================================================
//=====Query Linker=======
//====离线,用链表记录每个字符串有哪些查询=====
struct MISSION{
int id,x,nxt;
}mis[MAXN]; int cnt_mis;
int mis_head[MAXN];
void add_mis(int id,int x,int y){
mis[++cnt_mis].x = x;
mis[cnt_mis].id = id;
mis[cnt_mis].nxt = mis_head[y];
mis_head[y] = cnt_mis;
}
int ans[MAXN];
//=========================================================
//====BIT========
//===用树状数组维护dfs序上的区间和=====
struct BIT{
int a[MAXN];
int sum[MAXN];
inline void add(int x,int v){
a[x] += v;
for(int i = x;i<=N;i+=i&-i) sum[i] += v;
}
inline int inqry(int x,int y){
int rtn = 0;
for(int i=y;i;i-=i&-i)
rtn += sum[i];
for(int i=x-1;i;i-=i&-i)
rtn-=sum[i];
return rtn;
}
}Tree_Array;
//====================================================
//========Fail Tree==========
//=====fail树,搞dfs序,记录子树所在的区间===
struct EDGE{
int to,nxt;
}edge[MAXN]; int cnt_edge;
int fst[MAXN];
void addedge(int x,int y){
edge[++cnt_edge].to = y;
edge[cnt_edge].nxt = fst[x];
fst[x] = cnt_edge;
}
//==子树区间的左端点,右端点=======
int dfn_b[MAXN],dfn_e[MAXN],cnt_dfs;
void dfs(int now){
dfn_b[now] = ++cnt_dfs;
for(int tmp = fst[now];tmp;tmp=edge[tmp].nxt){
int aim = edge[tmp].to;
dfs(aim);
}
dfn_e[now] = cnt_dfs;
}
//==============================================================
//====AC Automaton======
struct ACAM{
int son[MAXN][26],fail[MAXN];
int root,cnt_node;
inline void init(){root = cnt_node = 1;}
int que[MAXN],head,tail;
inline void bfs(){
head = tail = 0;
int now = root;
for(int x=0;x<26;++x){
if(son[now][x]) que[tail++] = son[now][x];
(son[now][x]?fail[son[now][x]]:son[now][x]) = now;
}
while(head^tail){
now = que[head++];
addedge(fail[now],now);
for(int x=0;x<26;++x){
if(son[now][x]) que[tail++] = son[now][x];
(son[now][x]?
fail[son[now][x]] : son[now][x]) = son[ fail[now] ][x];
}
}
}
}YJQ;
char s[MAXN];//读入的字符串
int id2[MAXN],cnt_id2;
//id2[i]:编号为i的字符串在trie树上的终止节点
int iid2[MAXN];
//iid2[i]:i号节点对应的字符串
int s_id[MAXN];
//s_id[i]: 读入字符串中的第i个字符对应的节点标号
int pre[MAXN]; //trie树上的父节点
inline void YJQ_insert(){
int now = YJQ.root;
int lth = strlen(s);
for(int i=0;i<lth;++i){
char x = s[i];
if(x == 'P')
id2[++cnt_id2] = now , iid2[now] = cnt_id2;
if(x == 'B') now = pre[now] ;
if(x>='a'&&x<='z'){
int k = x-'a';
if(!YJQ.son[now][k]) YJQ.son[now][k] = ++YJQ.cnt_node;
pre[YJQ.son[now][k]] = now , now = YJQ.son[now][k];
s_id[i] = now;
}
}
}
inline void prep(){
it.read_str(s);
YJQ_insert();
YJQ.bfs();
}
//============================================================
//===Main====
int stk[MAXN],top; //在最后遍历trie树时的当前字符串
int main(){
YJQ.init();
prep();
N = YJQ.cnt_node;
n=it;
for(int i=1;i<=n;++i){
int u=it,v=it;
add_mis(i,u,v);
}
dfs(YJQ.root);//QAQQQQ
int Len = strlen(s);
for(int i=0;i<Len;++i){
char x = s[i];
if(x>='a'&&x<='z') Tree_Array.add(dfn_b[s_id[i]],1) , stk[++top] = s_id[i];
if(x=='B') Tree_Array.add(dfn_b[stk[top]],-1) , --top;
if(x=='P'){
int now = iid2[stk[top]];
for(int tmp = mis_head[now];tmp;tmp=mis[tmp].nxt){
int aim = id2[mis[tmp].x];
ans[mis[tmp].id] = Tree_Array.inqry(dfn_b[aim],dfn_e[aim]);
}
}
}
for(int i=1;i<=n;++i)
it.out(ans[i]);
return 0;
}