链接
题解
群大佬太强了
这题的做法是离线,把查询串建成 A C AC AC自动机,然后对给定的字典树进行 d f s dfs dfs,同时在自动机上跑,字典树上每个点都对应跑到 A C AC AC自动机上某个点 p p p,那么显然此时 p p p以及 p p p在 f a i l fail fail树上的所有祖先都匹配到了,最直接的想法是把从 p p p到根节点上的权值都 + 1 +1 +1,这个看起来像是 l c t lct lct或者树链剖分;但其实 p p p影响到的也只有 p p p在 f a i l fail fail树上的祖先,因此我直接给 p p p的权值 + 1 +1 +1,查询的时候查询子树和就行了
代码
#include <bits/stdc++.h>
#define eps 1e-8
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define cl(x) memset(x,0,sizeof(x))
#define mod 1073741824ll
#define maxn 400010
#define maxe 400010
using namespace std;
typedef long long ll;
struct Graph
{
int etot, head[maxn], to[maxe], next[maxe];
void adde(int a, int b)
{to[++etot]=b;next[etot]=head[a];head[a]=etot;}
}G;
struct ACautomaton
{
int trie[maxn][30], tot, fail[maxn];
void clear(){tot=1;}
int insert(char *r, int len)
{
auto pos=1;
for(auto i=1;i<=len;i++)
pos = trie[pos][r[i]] ? trie[pos][r[i]] : trie[pos][r[i]]=++tot;
return pos;
}
int append(int pos, int x)
{
if(trie[pos][x])return trie[pos][x];
else return trie[pos][x]=++tot;
}
void build()
{
queue<int> q;
int u, v, f;
q.push(1);
while(!q.empty())
{
u=q.front(); q.pop();
for(auto i=1;i<=26;i++)
if(trie[u][i])
{
v=trie[u][i];
for(f=fail[u];f and !trie[f][i];f=fail[f]);
fail[v] = f ? trie[f][i] : 1;
q.push(v);
}
}
}
int move(int pos, int c)
{
for(;pos and !trie[pos][c];pos=fail[pos]);
return pos ? trie[pos][c] : 1;
}
}trie, aca;
struct BIT
{
int bit[maxn], n;
void init(int N){n=N;}
int lowbit(int x){return x&-x;}
void add(int pos, int v){for(;pos<=n;pos+=lowbit(pos))bit[pos]+=v;}
int sum(int pos)
{
int ans=0;
for(;pos;pos-=lowbit(pos))ans+=bit[pos];
return ans;
}
}bit;
int tid[maxn], ltid[maxn], rtid[maxn], tim;
void dfs(int pos)
{
tid[pos]=ltid[pos]=++tim;
for(auto p=G.head[pos];p;p=G.next[p])
dfs(G.to[p]);
rtid[pos]=tim;
}
int ans[maxn], aca_endp[maxn], trie_endp[maxn];
vector<int> q[maxn];
void solve(int pos, int aca_pos)
{
bit.add(tid[aca_pos],+1);
for(auto x:q[pos])
ans[x] = bit.sum(rtid[aca_endp[x]]) - bit.sum(ltid[aca_endp[x]]-1);
for(int i=1;i<=26;i++)
if(trie.trie[pos][i])
solve(trie.trie[pos][i],aca.move(aca_pos,i));
bit.add(tid[aca_pos],-1);
}
char s[maxn];
int main()
{
ios::sync_with_stdio(false);
int i, j, n, m, type;
char c;
trie.clear();
aca.clear();
cin>>n;
for(i=1;i<=n;i++)
{
cin>>type;
if(type==1)
{
cin>>c;
trie_endp[i]=trie.append(1,int(c-'a'+1));
}
else
{
cin>>j>>c;
trie_endp[i]=trie.append(trie_endp[j],int(c-'a'+1));
}
}
cin>>m;
for(i=1;i<=m;i++)
{
cin>>j>>s+1;
int len=strlen(s+1);
for(int j=1;j<=len;j++)s[j]=s[j]-'a'+1;
aca_endp[i] = aca.insert(s,len);
q[trie_endp[j]].push_back(i);
}
aca.build();
for(i=2;i<=aca.tot;i++)G.adde(aca.fail[i],i);
dfs(1);
bit.init(tim);
solve(1,1);
for(i=1;i<=m;i++)cout<<ans[i]<<'\n';
return 0;
}