题面
题解
两个后缀的$LCS$,就是在后缀树上的$LCA$的深度。对于同属于一个$LCA$的点,我们只需要在原序列上连续的两个(实现上,直接在插进去的时候找就可以了,要是遍历一遍复杂度就假了)
启发式合并。
#include<cstdio> #include<iostream> #include<cstring> #include<set> #include<algorithm> #include<vector> #define ri register int #define N 100500 using namespace std; int n,q,cc,ans[N]; char s[N]; struct ques { int l,r,id; bool operator < (const ques &rhs) const { return r<rhs.r || (r==rhs.r && l<rhs.l); } } qu[N]; struct pir{ int l,r,v; bool operator < (const pir &rhs) const { return r<rhs.r || (r==rhs.r && l<rhs.l); } } pp[N<<5]; struct SAM{ int ch[N<<1][2]; int ff[N<<1],len[N<<1]; int las,tot; vector<int> son[N<<1]; set<int> endp[N<<1]; void clear() { las=tot=1; } void extend(int c){ int p=las,np=++tot; las=tot; len[np]=len[p]+1; while (p && ch[p][c]==0) ch[p][c]=np,p=ff[p]; if (!p) { ff[np]=1; } else { int q=ch[p][c]; if (len[q]==len[p]+1) { ff[np]=q; } else { int nq=++tot; len[nq]=len[p]+1; ff[nq]=ff[q]; for (ri i=0;i<2;i++) ch[nq][i]=ch[q][i]; ff[np]=ff[q]=nq; while (p && ch[p][c]==q) ch[p][c]=nq,p=ff[p]; } } endp[np].insert(len[np]); } void maketree() { for (ri i=1;i<=tot;i++) son[ff[i]].push_back(i); } void merge(int x) { set<int> :: iterator it,it2,itp,itq; for (ri i=0;i<son[x].size();i++) { merge(son[x][i]); if (endp[x].size()<endp[son[x][i]].size()) swap(endp[x],endp[son[x][i]]); for (it=endp[son[x][i]].begin();it!=endp[son[x][i]].end();++it) { endp[x].insert(*it); it2=endp[x].lower_bound(*it); itq=itp=it2; if (itp!=endp[x].begin()) { --itp; pp[++cc]=(pir){*itp,*it,len[x]}; } { itq++; if (itq!=endp[x].end()) pp[++cc]=(pir){*it,*itq,len[x]}; } endp[x].erase(*it); } for (it=endp[son[x][i]].begin();it!=endp[son[x][i]].end();++it) endp[x].insert(*it); } } } sam; struct Fenwick{ int a[N]; void insert(int loc,int v) { loc=n-loc+1; for (ri i=loc;i<=n;i+=(i&(-i))) a[i]=max(a[i],v); } int find(int loc) { loc=n-loc+1; int ans=0; for (ri i=loc;i;i-=(i&(-i))) ans=max(ans,a[i]); return ans; } } fg; int main(){ scanf("%d %d",&n,&q); sam.clear(); scanf("%s",s+1); int l=strlen(s+1); for (ri i=1;i<=l;i++) sam.extend(s[i]-'0'); for (ri i=1;i<=q;i++) { scanf("%d %d",&qu[i].l,&qu[i].r); qu[i].id=i; } sam.maketree(); cc=0; sam.merge(1); sort(qu+1,qu+q+1); sort(pp+1,pp+cc+1); int p=1; for (ri i=1;i<=q;i++) { while (pp[p].r<=qu[i].r && p<=cc) fg.insert(pp[p].l,pp[p].v),p++; ans[qu[i].id]=fg.find(qu[i].l); } for (ri i=1;i<=q;i++) printf("%d ",ans[i]); return 0; }