「HAOI2018」字串覆蓋
阿新 • • 發佈:2021-01-03
顯然的貪心就是儘可能取位置靠前的點
那麼問題轉化成了維護另一個子串的 \(endpos\) 在這個子串的出現位置
按照古老的套路就是把一個建出來自動機另一個跑匹配
如果 \(l_{ed[r]}<r-l+1\) 那麼答案就是 \(0\)
反之考慮當前的點的在 \([tl,tr]\) 中所有的 \(endpos\)
查詢的話複雜度是 \(\frac{len_1}{len_2}\times \log_n\)
資料大的時候顯然能過,但是資料小的時候會完蛋
那麼考慮重新維護一個 \(f_{len,i,j}\) 表示當前字串是 \(S[i,i+len-1]\) ,後面的 \(2^j\) 的字串的位置,同時記錄 \(sum_{len,i,j}\) 為所有的 \(pos\) 之和
每個詢問倍增跳出來所有的位置和求和即可
#include<bits/stdc++.h> using namespace std; #define ll long long #define reg register #define ull unsigned long long namespace yspm{ inline int read(){ int res=0,f=1; char k; while(!isdigit(k=getchar())) if(k=='-') f=-1; while(isdigit(k)) res=res*10+k-'0',k=getchar(); return res*f; } const int N=1e5+10,M=N<<1,SZ=M*40; int son[M][26],bz[M][20],len[M],tot=1,las=1,fa[M],sum[SZ],ls[SZ],rs[SZ],num,rt[M],n; char s[N],t[N]; inline void push_up(int x){return sum[x]=sum[ls[x]]+sum[rs[x]],void();} inline void upd(int &p,int l,int r,int pos){ if(!p) p=++num; if(l==r) return sum[p]=1,void(); int mid=(l+r)>>1; if(pos<=mid) upd(ls[p],l,mid,pos); else upd(rs[p],mid+1,r,pos); return push_up(p); } inline int merge(int x,int y,int l,int r){ if(!x||!y) return x+y; int p=++num; if(l==r) return sum[p]=sum[x]|sum[y],p; int mid=(l+r)>>1; ls[p]=merge(ls[x],ls[y],l,mid); rs[p]=merge(rs[x],rs[y],mid+1,r); return push_up(p),p; } inline void extend(int x,int id){ int tmp=las,np=las=++tot; len[np]=len[tmp]+1; upd(rt[np],1,n,id); while(!son[tmp][x]) son[tmp][x]=np,tmp=fa[tmp]; if(!tmp) return fa[np]=1,void(); int q=son[tmp][x]; if(len[q]==len[tmp]+1) return fa[np]=q,void(); int clone=++tot; len[clone]=len[tmp]+1; for(reg int i=0;i<26;++i) son[clone][i]=son[q][i]; fa[clone]=fa[q]; fa[q]=fa[np]=clone; while(son[tmp][x]==q) son[tmp][x]=clone,tmp=fa[tmp]; return ; } struct edge{int to,nxt;}e[M<<1]; int head[M],cnt; inline void add(int u,int v){ e[++cnt].to=v; e[cnt].nxt=head[u]; return head[u]=cnt,void(); } inline void dfs(int x){ for(reg int i=1;i<=19;++i) bz[x][i]=bz[bz[x][i-1]][i-1]; for(reg int i=head[x];i;i=e[i].nxt){ bz[e[i].to][0]=x; dfs(e[i].to); rt[x]=merge(rt[x],rt[e[i].to],1,n); }return ; } int ped[N],led[N]; ll ans[N],k; ull hs[N],bas=13331,p[N]; inline int findpos(int l,int r){ reg int now=ped[r]; for(reg int i=19;~i;--i) if(len[bz[now][i]]>=r-l+1) now=bz[now][i]; return now; } inline int findfir(reg int p,reg int l,reg int r,reg int st,reg int ed){ if(!p) return -1; if(l==r) return l; reg int mid=(l+r)>>1,res=-1; if(st<=mid) res=findfir(ls[p],l,mid,st,ed); if(res!=-1) return res; if(ed>mid) res=findfir(rs[p],mid+1,r,st,ed); return res; } unordered_map<ull,vector<int> > mp; inline ull calc(reg int l,reg int r){return hs[r]-hs[l-1]*p[r-l+1];} struct node{ int id,pos,st,ed; node(){} node(reg int xx,reg int yy,reg int ww,reg int zz){id=xx; st=yy; ed=ww; pos=zz; return ;} }; struct nd{ int pos,ct; ll sum; nd(){} nd(reg int xx,reg int yy,reg int zz){pos=xx; sum=yy; ct=zz;} nd operator+(const nd &a)const{return nd(a.pos,sum+a.sum,ct+a.ct);} }nxt[N][20]; vector<node> q[60]; vector<int> tmp; signed main(){ n=read(); k=read(); scanf("%s%s",s+1,t+1); for(reg int i=1;i<=n;++i) extend(s[i]-'a',i); for(reg int i=1;i<=tot;++i) add(fa[i],i); dfs(1); int now=1,nl=0; for(reg int i=1;i<=n;++i){ if(son[now][t[i]-'a']) now=son[now][t[i]-'a'],nl++; else{ while(!son[now][t[i]-'a']&&now) now=fa[now]; if(!now) now=1,nl=0; else nl=len[now]+1,now=son[now][t[i]-'a']; } ped[i]=now; led[i]=nl; } reg int l1,r1,l2,r2,Q=read(); for(reg int i=1;i<=Q;++i){ l1=read(),r1=read(),l2=read(),r2=read(); if(led[r2]<r2-l2+1||r1-l1+1<l2-r2+1){ans[i]=0; continue;} now=findpos(l2,r2); if(r2-l2+1>50){ reg ll res=0; reg int p=findfir(rt[now],1,n,l1+(r2-l2+1)-1,r1); if(p==-1){ans[i]=0; continue;} res+=k-(p-(r2-l2+1)+1); p+=r2-l2+1; while(p<=r1&&p!=-1){ p=findfir(rt[now],1,n,p,r1); if(p!=-1) res+=k-(p-(r2-l2+1)+1),p+=r2-l2+1; } ans[i]=res; }else q[r2-l2+1].push_back(node(i,l1,r1,now)); } p[0]=1; for(reg int i=1;i<=n;++i) p[i]=p[i-1]*bas,hs[i]=hs[i-1]*bas+s[i]; for(reg int len=1;len<=50;++len){ if(!q[len].size()) continue; mp.clear(); for(reg int i=len;i<=n;++i){ ull res=hs[i]-hs[i-len]*p[len]; nxt[i][0]=(nd){0,i-len+1,1}; if(mp.count(res)){ reg int r=-1; for(reg int j=mp[res].size()-1;~j;--j){ if(mp[res][j]<=i-len){r=j;break;} } while(r>=0) if(nxt[mp[res][r]][0].pos==0) nxt[mp[res][r]][0].pos=i,--r; else break; }mp[res].push_back(i); } for(reg int i=n;i>=len;--i){ for(reg int j=1;nxt[nxt[i][j-1].pos][j-1].pos;++j) nxt[i][j]=nxt[i][j-1]+nxt[nxt[i][j-1].pos][j-1]; } for(auto p:q[len]){ reg int st=findfir(rt[p.pos],1,n,p.st+len-1,p.ed); if(st==-1){ans[p.id]=0;continue;} reg ll s=0,c=0; for(reg int i=19;~i;--i){ if(nxt[st][i].pos&&nxt[st][i].pos<=p.ed){ s+=nxt[st][i].sum,c+=nxt[st][i].ct; st=nxt[st][i].pos; } } c++; s+=st-len+1; ans[p.id]=1ll*k*c-s; } for(reg int i=len;i<=n;++i) memset(nxt[i],0,sizeof(nxt[i])); } for(reg int i=1;i<=Q;++i) printf("%lld\n",ans[i]); return 0; } } signed main(){return yspm::main();}