Deepin 安裝 xRDP,Window使用RDP遠端連線
Luogu4770 [NOI2018]你的名字
\(SAM+LCT+\)倍增
好歹自己切了一道字串黑題,這幾天字串沒白頹。
觀察原問題,如果模式串不是區間形式的話,很容易想到一個做法,就是對於輸入串每一個\(r\)位置,除去\(r\)所在的字尾中不滿足條件的字尾,顯然不滿足條件的字尾一定是一段區間,所以從\(r\)字尾在\(SAM\)的\(parent\)樹上的匹配的最深位置\(x\)到\(root\)路徑中所有的字尾都需要砍掉。
然而模式串是一段區間,可以發現,不滿足條件的串仍然是\(x \rightarrow root\)路徑上一個位置\(y\)到\(root\)的路徑,因為新的不滿足條件的字尾一定是原問題的子集。
那麼我們考慮找到那個節點,也就是說,該節點代表的集合中存在串\(s\),使得它在\(r\)之前最後出現的位置的左端點\(L \ge l\)。
參考Luogu6292 區間本質不同子串個數的做法,將\(r\)指標一位一位掃過去,同時用\(LCT\)更新最右的右端點。
同時,在\(parent\)樹上,節點的\(l\)端點在\(x \rightarrow root\)上一定單調遞增,因為對於最右\(r\)端點,顯然祖先一定不小於子孫,對於長度,祖先又比子孫小。
既然具有了單調性,我們就可以考慮倍增了,向\(L<l\)的最淺節點跳。在細節上,注意我們最終跳到的節點可能會存在一部分子串滿足題意,這些必須統計。
還有一個問題需要處理,就是對於輸入的串,即使除去了不滿足題意的串,其自身的串依然會存在重複情況,對此,我們對輸入串仍需要建立\(SAM\)。
那麼我們在\(parent\)樹上打標記,我們已經找出了一個字尾長度在\([1,t]\)範圍內是不合法的,這在新的\(SAM\)上仍然對應一個節點到根的路徑,再次倍增。
最後一次\(DFS\)統計答案即可。
\(Code:\)
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<string> #include<vector> #define pr pair<int,int> #define mp make_pair #define ll long long #define IT vector< pr > :: iterator #define N 500005 #define qN 100005 using namespace std; int l,r; int lth[qN],g[N << 1]; ll ans[qN]; char s[N]; string T[qN]; vector< pr >e[N]; int n,q; struct edge { int nxt,v; edge (int Nxt=0,int V=0) { nxt=Nxt,v=V; } }E[N << 1]; int tot,fr[N << 1]; void add(int x,int y) { ++tot; E[tot]=edge(fr[x],y),fr[x]=tot; } struct SAM { int lst=1,cnt=1,tr[N << 1][26],pre[N << 1],len[N << 1]; int f[N << 1][22]; void ins(int c) { int p=lst,q,np; lst=np=++cnt; len[np]=len[p]+1; for (;p && !tr[p][c];p=pre[p]) tr[p][c]=np; if (!p) pre[np]=1; else { q=tr[p][c]; if (len[p]+1==len[q]) pre[np]=q; else { int g=++cnt; memcpy(tr[g],tr[q],sizeof(tr[q])); len[g]=len[p]+1,pre[g]=pre[q]; for (;p && tr[p][c]==q;p=pre[p]) tr[p][c]=g; pre[np]=pre[q]=g; } } } void Do_st() { for (int i=1;i<=cnt;++i) f[i][0]=pre[i]; for (int j=1;j<=20;++j) for (int i=1;i<=cnt;++i) f[i][j]=f[f[i][j-1]][j-1]; } void build() { for (int i=2;i<=cnt;++i) add(pre[i],i); } void Clear() { memset(tr,0,26*(cnt+1)*sizeof(int)); memset(g,0,(cnt+1)*sizeof(int)); memset(fr,0,(cnt+1)*sizeof(int)); tot=0,cnt=lst=1; } }S1,S2; #define ls(x) a[x].ch[0] #define rs(x) a[x].ch[1] #define fa(x) a[x].f #define tag(x) a[x].cltg #define col(x) a[x].cl struct LCT { int ch[2],f,cltg,cl; }a[N << 1]; int Q[N << 1]; int id(int x) { return ls(fa(x))==x?0:1; } bool isrt(int x) { return ls(fa(x))!=x && rs(fa(x))!=x; } void connect(int x,int F,int son) { fa(x)=F; a[F].ch[son]=x; } void rot(int x) { int y=fa(x),r=fa(y); int yson=id(x),rson=id(y); if (isrt(y)) fa(x)=r; else connect(x,r,rson); connect(a[x].ch[yson^1],y,yson); connect(y,x,yson^1); } void push_tag(int x,int z) { if (!x) return; tag(x)=col(x)=z; } void push_down(int x) { if (tag(x)) { push_tag(ls(x),tag(x)); push_tag(rs(x),tag(x)); tag(x)=0; } } void splay(int x) { int g=x,k=0; Q[++k]=x; while (!isrt(g)) g=fa(g),Q[++k]=g; while (k) push_down(Q[k--]); while (!isrt(x)) { int y=fa(x); if (isrt(y)) rot(x); else if (id(x)==id(y)) rot(y),rot(x); else rot(x),rot(x); } } void access(int x,int r) { int y; for (y=0;x;y=x,x=fa(x)) { splay(x); rs(x)=y; } push_tag(y,r); } int Col(int x) { splay(x); return col(x); } void Dfs(int u,int w) { for (int i=fr[u];i;i=E[i].nxt) { int v=E[i].v; Dfs(v,w); g[u]=max(g[u],g[v]); } ans[w]+=S2.len[u]-max(S2.len[S2.pre[u]],min(g[u],S2.len[u])); } int main() { scanf("%s",s+1); n=strlen(s+1); for (int i=1;i<=n;++i) S1.ins(s[i]-'a'); S1.Do_st(); for (int i=2;i<=S1.cnt;++i) fa(i)=S1.pre[i]; scanf("%d",&q); for (int i=1;i<=q;++i) { cin >> T[i]; lth[i]=T[i].length(); scanf("%d%d",&l,&r); e[r].push_back(mp(l,i)); } int st=1; for (int i=1;i<=n;++i) { st=S1.tr[st][s[i]-'a']; access(st,i); for (IT it=e[i].begin();it!=e[i].end();++it) { S2.Clear(); int l=it->first,w=it->second,s0=1,st0=1,nlen=0; for (int j=0;j<lth[w];++j) S2.ins(T[w][j]-'a'); S2.Do_st(); for (int j=0;j<lth[w];++j) { int c=T[w][j]-'a'; st0=S2.tr[st0][c]; if (!S1.tr[1][c]) s0=1,nlen=0; else { while (!S1.tr[s0][c]) s0=S1.pre[s0],nlen=S1.len[s0]; s0=S1.tr[s0][c]; ++nlen; int tans; if (Col(s0)-nlen+1>=l) tans=nlen; else { int F=s0; for (int j=20;j>=0;--j) if (S1.f[F][j] && Col(S1.f[F][j])-S1.len[S1.f[F][j]]+1<l) F=S1.f[F][j]; tans=max(Col(F)-l+1,S1.len[S1.f[F][0]]); } int k=st0; for (int j=20;j>=0;--j) if (S2.f[k][j] && S2.len[S2.f[k][j]]>=tans) k=S2.f[k][j]; g[k]=max(g[k],tans); } } S2.build(); Dfs(1,w); } } for (int i=1;i<=q;++i) printf("%lld\n",ans[i]); return 0; }