bzoj3413 匹配
题解:
最开始我想倒建倒查,结果发现需要另开线段树维护,结果算法退化了……
说正解。
正建正查。
线段树合并+SAM。
将询问串放在SAM中,判断是否有匹配。
然后设定边界就可以了。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 100050 #define ll long long const int inf = 0x3f3f3f3f; char s[N]; int n,m,len; struct node { int len,pre,trs[12]; }p[2*N]; int hed[2*N],cnt; ll ans = 0; struct segtree { int tot,siz[80*N],ls[80*N],rs[80*N],rt[2*N]; void insert(int &u,int l,int r,int qx) { u = ++tot; siz[u]++; if(l==r)return ; int mid = (l+r)>>1; if(qx<=mid)insert(ls[u],l,mid,qx); else insert(rs[u],mid+1,r,qx); } int merge(int l,int r) { if(!l||!r)return l+r; int u = ++tot; siz[u] = siz[l]+siz[r]; ls[u] = merge(ls[l],ls[r]); rs[u] = merge(rs[l],rs[r]); return u; } int query(int u,int l,int r,int ql,int qr) { if(!u)return 0; if(l==ql&&r==qr)return siz[u]; int mid = (l+r)>>1; if(qr<=mid)return query(ls[u],l,mid,ql,qr); else if(ql>mid)return query(rs[u],mid+1,r,ql,qr); else return query(ls[u],l,mid,ql,mid)+query(rs[u],mid+1,r,mid+1,qr); } int min_pos(int u,int l,int r) { if(l==r)return l; int mid = (l+r)>>1; if(siz[ls[u]])return min_pos(ls[u],l,mid); else return min_pos(rs[u],mid+1,r); } }tr; struct SAM { int las,tot; SAM(){las=tot=1;} void insert(int c,int k) { int np,nq,lp,lq; np=++tot; p[np].len = p[las].len+1; tr.insert(tr.rt[np],1,n,k); for(lp=las;lp&&!p[lp].trs[c];lp=p[lp].pre) p[lp].trs[c]=np; if(!lp)p[np].pre = 1; else { lq = p[lp].trs[c]; if(p[lq].len==p[lp].len+1)p[np].pre = lq; else { nq=++tot; p[nq]=p[lq]; p[nq].len = p[lp].len+1; p[lq].pre = p[np].pre = nq; while(p[lp].trs[c]==lq) { p[lp].trs[c]=nq; lp=p[lp].pre; } } } las = np; } int hs[2*N],topo[2*N]; void build() { for(int i=1;i<=tot;i++)hs[p[i].len]++; for(int i=1;i<=tot;i++)hs[i]+=hs[i-1]; for(int i=1;i<=tot;i++)topo[hs[p[i].len]--]=i; for(int i=tot;i>=1;i--) { int x = topo[i]; tr.rt[p[x].pre]=tr.merge(tr.rt[p[x].pre],tr.rt[x]); } } }sam; int main() { scanf("%d%s",&n,s+1); for(int i=1;i<=n;i++) sam.insert(s[i]-'0',i); sam.build(); scanf("%d",&m); while(m--) { scanf("%s",s+1); len = strlen(s+1); ans = 0; int endpos = inf,u = 1; for(int i=1;i<=len;i++) u = p[u].trs[s[i]-'0']; if(!u)ans = n; else { endpos = tr.min_pos(tr.rt[u],1,n); ans = endpos - len; } u = 1; for(int i=1;i<=len;i++) { u = p[u].trs[s[i]-'0']; if(!u)break; int qr = min(n,endpos-len+i); ans+=tr.query(tr.rt[u],1,n,1,qr); } printf("%lld\n",ans); } return 0; }