【题解】SP8093 JZPGYZ - Sevenk Love Oimaster
SP8093 JZPGYZ - Sevenk Love Oimaster
\(\text{Solution:}\)
坑人的 spoj 不给数据)傻逼的笔者做到了 CF204E Little Elephant and Strings 才仔细想明白自己为啥子树数颜色错了好久……
显然,建立好广义 SAM 并且给属于不同串的节点染色之后,就变成了一个 parent 树上的子树数颜色问题。
那这个问题长得很 HH的项链 啊。考虑把每一个点的子树都求出来,设 \(cpos[i]\) 表示颜色 \(i\) 上此出现的 dfs序 是什么。
由于我们根据 dfs序 把原问题转化到的序列上,所以我们也要保证做的时候 dfs序 单调,而不是点编号。
然后就是一个简单的数颜色啦:对当前 dfs序,单点 \(+1\) 并且把上一次出现位置 \(-1...\) 但愉快写完后发现自己 WA 了,还不能看数据也不知道答案偏大偏小。
那问题就很玄学了,死活不知道哪里写错。实际上:你颜色都是非负的,但这样处理会把没有颜色的节点当成一种颜色,答案就错了。
剩下就没啥问题了 一个树状数组的事情罢了。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+10;
inline int lowbit(int x){return x&(-x);}
int tr[N];
namespace SAM{
int len[N],pa[N],ch[N][26],tag[N];
int last=1,tot=1,dfn[N],dfstime;
int pos[N],cpos[N],siz[N],num[N];
int rk[N],colf[N];
vector<int>G[N],qr[N];
void insert(const int &c,const int &col){
int p=last;
int np=++tot;
last=tot;len[np]=len[p]+1;tag[np]=col;
for(;p&&!ch[p][c];p=pa[p])ch[p][c]=np;
if(!p)pa[np]=1;
else{
int q=ch[p][c];
if(len[q]==len[p]+1)pa[np]=q;
else{
int nq=++tot;
len[nq]=len[p]+1;
memcpy(ch[nq],ch[q],sizeof ch[q]);
pa[nq]=pa[q];pa[q]=pa[np]=nq;
for(;p&&ch[p][c]==q;p=pa[p])ch[p][c]=nq;
}
}
}
void dfs(int x){
dfn[x]=++dfstime;siz[x]=1;rk[dfstime]=x;
colf[dfstime]=tag[x];
for(auto i:G[x])dfs(i),siz[x]+=siz[i];
}
void change(int x,int v){
while(x<=tot)tr[x]+=v,x+=lowbit(x);
}
int query(int x){
int res=0;
while(x)res+=tr[x],x-=lowbit(x);
return res;
}
void BuildTree(){
for(int i=2;i<=tot;++i)G[pa[i]].push_back(i);
dfs(1);
for(int i=1;i<=tot;++i)qr[dfn[i]+siz[i]-1].push_back(i);
for(int i=1;i<=tot;++i){
if(!cpos[colf[i]])cpos[colf[i]]=i;
pos[i]=cpos[colf[i]];cpos[colf[i]]=i;
}
for(int i=1;i<=tot;++i){
if(!colf[i])continue;
change(i,1);
if(i!=pos[i])change(pos[i],-1);
for(auto v:qr[i]){
// printf("(%d %d)\n",i,dfn[v]);
num[v]=query(i)-query(dfn[v]-1);
// puts("?");
}
}
}
}
using namespace SAM;
int n,m;
char s[N];
signed main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;++i){
scanf("%s",s+1);
last=1;
int len=strlen(s+1);
for(int j=1;j<=len;++j)insert(s[j]-'a',i);
}
BuildTree();
// for(int i=1;i<=tot;++i)cout<<num[i]<<endl;
for(int i=1;i<=m;++i){
scanf("%s",s+1);
int len=strlen(s+1);
int node=1,fg=0;
for(int j=1;j<=len&&!fg;++j){
int v=s[j]-'a';
if(ch[node][v])node=ch[node][v];
else{puts("0");fg=1;break;}
}
if(!fg)printf("%lld\n",num[node]);
}
return 0;
}