【BZOJ3413】匹配 离线+后缀树+树状数组
【BZOJ3413】匹配
Description
Input
第一行包含一个整数n(≤100000)。
第二行是长度为n的由0到9组成的字符串。
第三行是一个整数m。
接下来m≤5·10行,第i行是一个由0到9组成的字符串s,保证单行字符串长度小于等于10^5,所有字符串长度和小于等于3·10^6
Output
输出m行,第i行表示第si和S匹配所比较的次数。
Sample Input
7
1090901
4
87650
0901
109
090
1090901
4
87650
0901
109
090
Sample Output
7
10
3
4
10
3
4
题解:题目是问你截止到匹配之前,A串的每个位置与B串的LCP+1之和。这要利用到一个性质,两个后缀的lcp长度等于后缀树上两个点的lca的mx值。所以我们对A串的反串建立后缀自动机,得到后缀树,然后将B串放到后缀树中进行匹配(后缀树中匹配不同于后缀自动机中的匹配,实现比较复杂,方法也有很多,可以看代码)。如果没有成功匹配,则我们取最后一个成功匹配的节点,从这个点沿着到根的路径一路走上去跑一个树形DP即可。如果匹配成功,我们记录一下匹配成功的节点以及匹配位置,然后离线处理。我们将原串中的点一个一个加到后缀树中去,用树状数组维护DFS序得到子树和,处理询问时依旧跑类似于树形DP的东西即可。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> using namespace std; typedef long long ll; const int N=200010; int n,m,tot,last,cnt; char S[N],T[N]; int ch[N][10],mx[N],pre[N],p1[N],p2[N],mn[N],pos[N],qos[N],len[N],s[N],L[N],R[N],son[N][10],siz[N]; vector<int> q[N]; vector<int>::iterator it; int f[N]; ll ans[N]; inline int extend(int x) { int p=last,np=++tot; last=np; mx[np]=mx[p]+1,siz[np]=1; for(;p&&!ch[p][x];p=pre[p]) ch[p][x]=np; if(!p) ch[1][x]=np,pre[np]=1; else { int q=ch[p][x]; if(mx[q]==mx[p]+1) pre[np]=q; else { int nq=++tot; mx[nq]=mx[p]+1,R[nq]=R[q]-(mx[q]-mx[p]-1); pre[nq]=pre[q],pre[np]=pre[q]=nq; memcpy(ch[nq],ch[q],sizeof(ch[q])); for(;p&&ch[p][x]==q;p=pre[p]) ch[p][x]=nq; } } return np; } void dfs(int x) { p1[x]=++p2[0]; for(int i=0,y;i<10;i++) if((y=son[x][i])) dfs(y),siz[x]+=siz[y],mn[x]=min(mn[x],mn[y]); p2[x]=p2[0]; } inline void updata(int x) { for(int i=x;i<=tot;i+=i&-i) s[i]++; } inline int query(int x) { int ret=0,i; for(i=x;i;i-=i&-i) ret+=s[i]; return ret; } int main() { scanf("%d%s",&n,S); int i,j,x,y; memset(mn,0x3f,sizeof(mn)); tot=last=1; for(i=n-1;i>=0;i--) pos[i]=extend(S[i]-'0'),mn[pos[i]]=i,R[pos[i]]=n-1; for(i=2;i<=tot;i++) L[i]=R[i]-(mx[i]-mx[pre[i]])+1,son[pre[i]][S[L[i]]-'0']=i; scanf("%d",&m); dfs(1); R[1]=-1; for(i=1;i<=m;i++) { scanf("%s",T),len[i]=strlen(T); for(x=1,j=y=0;j<len[i];j++) { if(y<=R[x]) { if(S[y]==T[j]) y++; else break; } else { if(son[x][T[j]-'0']) x=son[x][T[j]-'0'],y=L[x]+1; else break; } } qos[i]=x; if(j<len[i]) { if(x==1) ans[i]=n; else { ans[i]=n+1ll*siz[x]*min(mx[x]-mx[pre[x]],y-L[x]); for(x=pre[x];x!=1;x=pre[x]) ans[i]+=1ll*(mx[x]-mx[pre[x]])*siz[x]; } } else { ans[i]=len[i]+mn[x]; if(mn[x]) q[mn[x]-1].push_back(i); } } for(i=0;i<n;i++) { updata(p1[pos[i]]); for(it=q[i].begin();it!=q[i].end();it++) { for(j=pre[qos[*it]];j;j=pre[j]) ans[*it]+=1ll*(mx[j]-mx[pre[j]])*(query(p2[j])-query(p1[j]-1)); } } for(i=1;i<=m;i++) printf("%lld\n",ans[i]); return 0; }
| 欢迎来原网站坐坐! >原文链接<