SAM维护的在线LCS
题目大意:
给定两个字符串,存在三种操作,分别是在a,b串末尾加一个字符串,和询问两串的LCS
题解:
Get新套路:把两串建在同一SAM上,将重合的位置合并为同一节点,再加个标记数组,如果两者的LCS标记都存在那么就直接更新答案.
注意标记需要沿father上传,每新建一个节点就打上标记并更新祖先
1 #include <algorithm> 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #define RG register 8 using namespace std; 9 const int N=5000005,M=10000005; 10 char S[N];int ch[M][3],fa[M],cur=1,cnt=1,ans=0,n=0,s[2][N],m=0,dis[M],pre[2][N],l[N]; 11 int mark[M];long long ret=0; 12 void updata(int p){ 13 while(fa[p] && (mark[p]&mark[fa[p]])!=mark[p]){ 14 if(mark[p]==3)ans=max(ans,dis[p]); 15 mark[fa[p]]|=mark[p]; 16 p=fa[p]; 17 } 18 if(mark[p]==3)ans=max(ans,dis[p]); 19 } 20 int build(int last,int k,int c) 21 { 22 cur=++cnt;dis[cur]=dis[last]+1; 23 RG int p=last; 24 for(;p && !ch[p][c];p=fa[p])ch[p][c]=cur; 25 if(!p)fa[cur]=1; 26 else{ 27 int q=ch[p][c]; 28 if(dis[q]==dis[p]+1)fa[cur]=q; 29 else{ 30 int nt=++cnt;dis[nt]=dis[p]+1; 31 memcpy(ch[nt],ch[q],sizeof(ch[q])); 32 fa[nt]=fa[q];fa[q]=fa[cur]=nt; 33 updata(q); /*不能忘记这个地方*/ 34 for(;ch[p][c]==q;p=fa[p])ch[p][c]=nt; 35 } 36 } 37 mark[cur]|=(1<<k); 38 updata(cur); 39 return cur; 40 } 41 void work() 42 { 43 int Q,fg0,fg1; 44 scanf("%d",&Q);scanf("%s",S+1); 45 pre[0][0]=pre[1][0]=1; 46 for(int i=1,x;i<=Q;i++){ 47 x=S[i]-'0'; 48 fg0=(x^ans)%2;fg1=((x^ans)>>1)%2;fg1++; 49 s[fg0][++l[fg0]]=fg1; 50 if(pre[fg0][l[fg0]-1]==pre[fg0^1][l[fg0]-1] && fg1==s[fg0^1][l[fg0]]){ 51 pre[fg0][l[fg0]]=pre[fg0^1][l[fg0]]; 52 mark[pre[fg0][l[fg0]]]|=(1<<fg0); 53 updata(pre[fg0][l[fg0]]); 54 } 55 else{ 56 pre[fg0][l[fg0]]=build(pre[fg0][l[fg0]-1],fg0,fg1); 57 } 58 ret+=ans; 59 } 60 printf("%lld\n",ret); 61 } 62 int main() 63 { 64 freopen("lcs.in","r",stdin); 65 freopen("lcs.out","w",stdout); 66 work(); 67 return 0; 68 }