LOJ #6041. 「雅禮集訓 2017 Day7」事情的相似度
阿新 • • 發佈:2021-11-14
題面傳送門
智商不夠,自動機和資料結構來湊。
考慮對原串建出SAM,那麼兩個字首的最長公共字尾就是他們在SAM上LCA的深度。
那麼我們其實要求的就是一段區間內的節點在一棵樹上的LCA的最大深度。
考慮離線,按照右端點排序。從左往右掃。
如果對於兩個節點\(u,v\)且\(u<v\),且它們在樹上處於同一深度,那麼\(u\)顯然是可以排除在外的。
所以我們用一個LCT維護這個parent tree,每次將一個點到根的路徑打通並將路徑上碰到的點放到樹狀陣列上維護,每次查詢在樹狀陣列上查詢字尾即可。
時間複雜度\(O(nlog^2n)\),然而常數小的出奇。時間瓶頸在LCT不在樹狀陣列的nlogn次修改
code:
#include<bits/stdc++.h> #define I inline #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define abs(x) ((x)>0?(x):-(x)) #define re register #define RI re int #define ll long long #define db double #define lb long db #define N 200000 #define M 300000 #define mod 998244353 #define Mod (mod-1) #define eps (1e-5) #define U unsigned int #define it iterator #define Gc() getchar() #define Me(x,y) memset(x,y,sizeof(x)) #define d(x,y) (m*(x-1)+(y)) #define R(n) (rand()*rand()%(n)+1) #define Pc(x) putchar(x) using namespace std; int n,m,x,y,Pl[N+5],Ans[N+5],d[N+5];char S[N+5]; struct Ques{int l,id;};vector<Ques> Q[N+5]; namespace BIT{ int F[N+5];I void Get(int x,int y){while(x<=n) F[x]=max(F[x],y),x+=x&-x;}I int Qry(int x){int Ans=0;while(x) Ans=max(Ans,F[x]),x-=x&-x;return Ans;} } namespace SAM{ int len[N+5],link[N+5],son[N+5][2],La=1,p,q,cnt=1;I void Ins(char c){ c-='0';p=La;La=++cnt;len[La]=len[p]+1;while(p&&!son[p][c]) son[p][c]=La,p=link[p];if(!p){link[La]=1;return;} q=son[p][c];if(len[q]==len[p]+1)link[La]=q;else{ link[++cnt]=link[q];link[q]=link[La]=cnt;memcpy(son[cnt],son[q],sizeof(son[q]));len[cnt]=len[p]+1;while(p&&son[p][c]==q)son[p][c]=cnt,p=link[p]; } } } namespace LCT{ int l[N+5],r[N+5],F[N+5],Fl[N+5],fa[N+5],st[N+5],sh;I int CD(int x){return l[fa[x]]==x||r[fa[x]]==x;}I int RS(int x){return r[fa[x]]==x;} I void RO(int x){int y=fa[x],z=fa[y],b=(RS(x)?l[x]:r[x]);CD(y)&&((RS(y)?r[z]:l[z])=x);RS(x)?(l[x]=y,r[y]=b):(r[x]=y,l[y]=b);fa[y]=x;fa[x]=z;b&&(fa[b]=y);} I void PF(int x,int w){x&&(F[x]=Fl[x]=w);}I void PD(int x){Fl[x]&&(PF(l[x],Fl[x]),PF(r[x],Fl[x]),Fl[x]=0);} I void SP(int x){int y=x;st[sh=1]=y;while(CD(y))y=fa[y],st[++sh]=y;while(sh) PD(st[sh--]);while(CD(x)) CD(fa[x])&&(RO(RS(x)^RS(fa[x])?x:fa[x]),0),RO(x);} I void AC(int x,int Id){int y=0;for(;x;x=fa[y=x]) SP(x),F[x]&&(/*printf("%d %d %d\n",Id,F[x],SAM::len[x]),*/BIT::Get(n-F[x]+1,SAM::len[x]),0),r[x]=y/*,printf(" %d %d ",x,y)*/;/*Pc('\n');*/PF(y,Id);} } int main(){ // freopen("1.in","r",stdin); RI i,j;scanf("%d%d",&n,&m);scanf("%s",S+1);for(i=1;i<=n;i++) SAM::Ins(S[i]),Pl[i]=SAM::La;for(i=1;i<=SAM::cnt;i++) LCT::fa[i]=SAM::link[i]; for(i=1;i<=m;i++)scanf("%d%d",&x,&y),Q[y].push_back((Ques){x,i});for(i=1;i<=n;i++)for(LCT::AC(Pl[i],i),j=0;j<Q[i].size();j++) Ans[Q[i][j].id]=BIT::Qry(n-Q[i][j].l+1); for(i=1;i<=m;i++) printf("%d\n",Ans[i]); }