TsinsenA1484. two strings(罗干)
传送门:http://www.tsinsen.com/A1484
思路:首先对于添加操作,后缀数组是很难实现的,因为这会改变很多个后缀。
所以换一个思路,把操作离线,倒着实现所有操作,这样插入就变成删除了。
删除操作就好做得多了。
先把B串接到A串后,用特殊字符隔开。
有询问时,还是向上向下二分出一个合法区间,查询区间内有多少个可以匹配的且存在的串。
因为要查区间和,用树状数组维护一下即可。
记录AB串的开始结束为止,删除时移动这些指针,然后把对应的被删除的后缀从树状数组中删除,“复活”的后缀加入树状数组(因为随着B串的缩短,有的后缀又可以匹配了)即可。
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> const int maxn=200010; using namespace std; int n,m,q[maxn],sta,eda,stb,edb,lena,t1[maxn],t2[maxn],rank[maxn],sa[maxn],sum[maxn],h[maxn],st[maxn][20],cnt,ans[maxn]; char a[maxn<<1],b[maxn<<1],s[maxn],ch[10]; struct bit{ int t[maxn]; void change(int x,int add){for (;x<=n;x+=x&(-x)) t[x]+=add;} int query(int x){int res=0;for (;x;x-=x&(-x)) res+=t[x];return res;} int query(int l,int r){return query(r)-query(l-1);}; }T; void getsa(){ int *x=t1,*y=t2,p=0,m=255; for (int i=1;i<=n;i++) sum[x[i]=s[i]]++; for (int i=1;i<=m;i++) sum[i]+=sum[i-1]; for (int i=1;i<=n;i++) sa[sum[x[i]]--]=i; for (int j=1;p<n;j<<=1,m=p){ p=0; for (int i=n-j+1;i<=n;i++) y[++p]=i; for (int i=1;i<=n;i++) if (sa[i]>j) y[++p]=sa[i]-j; memset(sum,0,sizeof(sum)); for (int i=1;i<=n;i++) sum[x[y[i]]]++; for (int i=1;i<=m;i++) sum[i]+=sum[i-1]; for (int i=n;i;i--) sa[sum[x[y[i]]]--]=y[i]; swap(x,y),x[sa[1]]=p=1; for (int i=2;i<=n;i++){ if (y[sa[i]]!=y[sa[i-1]]||y[sa[i]+j]!=y[sa[i-1]+j]) p++; x[sa[i]]=p; } } memcpy(rank,x,sizeof(rank));} void geth(){ for (int i=1,j=0;i<=n;i++){ if (rank[i]==1) continue; while (s[i+j]==s[sa[rank[i]-1]+j]) j++; h[rank[i]]=j; if (j) j--; } } void prework(){ for (int i=2;i<=n;++i) st[i][0]=h[i]; for (int k=1;k<=19;++k) for (int j=1<<k;j<=n;++j) st[j][k]=min(st[j][k-1],st[j-(1<<(k-1))][k-1]); } int getmin(int l,int r){ if (l>=r) return n-sa[r]+1; int k=log2(r-l); return min(st[r][k],st[l+(1<<k)][k]); } int findl(int x,int len){ int l=1,r=x,ans; while (l<=r){ int mid=(l+r)>>1; if (getmin(mid,x)>=len) ans=mid,r=mid-1; else l=mid+1; } return ans; } int findr(int x,int len){ int l=x,r=n,ans; while (l<=r){ int mid=(l+r)>>1; if (getmin(x,mid)>=len) ans=mid,l=mid+1; else r=mid-1; } return ans; } int query(){ int pos=rank[lena+stb],len=edb-stb+1; return T.query(findl(pos,len),findr(pos,len)); } void work(){ for (int i=1;i<=eda-edb+1;i++) T.change(rank[i],1); for (int i=m;i;i--){ if (q[i]==1) {if (eda-sta+1>=edb-stb+1) T.change(rank[sta],-1),++sta;} else if (q[i]==2) {if (eda-sta+1>=edb-stb+1) T.change(rank[eda-(edb-stb+1)+1],-1),--eda;} else if (q[i]==3) {++stb;if (eda-sta+1>=edb-stb+1) T.change(rank[eda-(edb-stb+1)+1],1);} else if (q[i]==4) {--edb;if (eda-sta+1>=edb-stb+1) T.change(rank[eda-(edb-stb+1)+1],1);} else ans[++cnt]=query(); } for (int i=cnt;i;i--) printf("%d\n",ans[i]); } int main(){ scanf("%s%s%d",a+maxn,b+maxn,&m); sta=stb=maxn;eda=maxn+strlen(a+maxn)-1;edb=maxn+strlen(b+maxn)-1; for (int i=1;i<=m;i++){ scanf("%d",&q[i]); if (q[i]==1) scanf("%s",ch),a[--sta]=ch[0]; else if (q[i]==2) scanf("%s",ch),a[++eda]=ch[0]; else if (q[i]==3) scanf("%s",ch),b[--stb]=ch[0]; else if (q[i]==4) scanf("%s",ch),b[++edb]=ch[0]; else continue; } for (int i=sta;i<=eda;i++) a[i-sta+1]=a[i];eda=eda-sta+1;sta=1;a[eda+1]=0; for (int i=stb;i<=edb;i++) b[i-stb+1]=b[i];edb=edb-stb+1;stb=1;b[edb+1]=0; for (int i=1;i<=eda;i++) s[++n]=a[i];s[++n]='$',lena=n; for (int i=1;i<=edb;i++) s[++n]=b[i];s[n+1]=0; getsa(),geth(),prework(),work(); return 0; }