[BZOJ3413]匹配

Description

img

Input

​ 第一行包含一个整数n(≤100000)。

​ 第二行是长度为n的由0到9组成的字符串。

​ 第三行是一个整数m。

​ 接下来m≤5·10行,第i行是一个由0到9组成的字符串s,保证单行字符串长度小于等于10^ 5,所有字符串长度和小于等于3·10^6

Output

输出m行,第i行表示第si和S匹配所比较的次数。

Sample Input

7
1090901
4
87650
0901
109
090

Sample Output

7
10
3
4

Solution

又一道码农题...

后缀自动机上线段树合并求出每个点的\(endpos\)集合的位置,然后拿串在\(SAM\)上面跑,随便乱搞一下就好了。

#include<bits/stdc++.h>
using namespace std;
 
void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
 
void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

const int maxn = 2e5+10;

int n,m,rt[maxn],sgt;
char s[maxn];

#define mid ((l+r)>>1)

struct Segment_Tree {
	int ls[maxn*30],rs[maxn*30],t[maxn*30];

	void modify(int &p,int l,int r,int x) {
		if(!p) p=++sgt;t[p]++;
		if(l==r) return ;
		if(x<=mid) modify(ls[p],l,mid,x);
		else modify(rs[p],mid+1,r,x);
	}

	int query(int p,int l,int r,int x,int y) {
		if(!p) return 0;
		if(x<=l&&r<=y) return t[p];
		int ans=0;
		if(x<=mid) ans+=query(ls[p],l,mid,x,y);
		if(y>mid) ans+=query(rs[p],mid+1,r,x,y);
		return ans;
	}

	int merge(int x,int y) {
		if(!x||!y) return x+y;
		int p=++sgt;
		t[p]=t[x]+t[y];
		ls[p]=merge(ls[x],ls[y]);
		rs[p]=merge(rs[x],rs[y]);
		return p;
	}
}SGT;

struct Suffix_Automaton {
	int qs,lstp,cnt;
	int tr[maxn][10],par[maxn],ml[maxn],t[maxn],r[maxn],vis[maxn],pos[maxn];

	void clear() {qs=lstp=cnt=1;}
	
	void append(int x,int v) {
		int p=lstp,np=++cnt;lstp=np;ml[np]=ml[p]+1;vis[np]=1;pos[np]=v;
		for(;p&&tr[p][x]==0;p=par[p]) tr[p][x]=np;
		if(!p) return par[np]=qs,void();
		int q=tr[p][x];
		if(ml[p]+1<ml[q]) {
			int nq=++cnt;ml[nq]=ml[p]+1;pos[nq]=pos[q];
			memcpy(tr[nq],tr[q],sizeof tr[nq]);
			par[nq]=par[q],par[q]=par[np]=nq;
			for(;p&&tr[p][x]==q;p=par[p]) tr[p][x]=nq;
		} else par[np]=q;
	}

	void prepare() {
		for(int i=1;i<=cnt;i++) t[ml[i]]++;
		for(int i=1;i<=n;i++) t[i]+=t[i-1];
		for(int i=1;i<=cnt;i++) r[t[ml[i]]--]=i;

		for(int i=cnt,v;i;i--) if(vis[v=r[i]]) SGT.modify(rt[v],1,n,ml[v]);
		for(int i=cnt,v;i;i--) if(par[v=r[i]]) rt[par[v]]=SGT.merge(rt[par[v]],rt[v]);
	}

	void solve() {
		scanf("%s",s+1);
		int k=strlen(s+1),now=qs,rr=0,ans=0,x;
		for(int i=1,v;i<=k;i++)
			if(tr[now][v=s[i]-'0']) now=tr[now][v];
			else {rr=n+1;break;}
		if(!rr) rr=pos[now]-k+1,ans=k;now=qs;
		for(int i=1,v;i<=k;i++) {
			if(tr[now][v=s[i]-'0']) now=tr[now][v];
			else break;
			ans+=x=SGT.query(rt[now],1,n,1,min(rr+i-2,n));
		}ans+=rr-1;write(ans);
	}
}SAM;

int main() {
	read(n);
	scanf("%s",s+1);SAM.clear();
	for(int i=1;i<=n;i++) SAM.append(s[i]-'0',i);
	SAM.prepare();
	read(m);while(m--) SAM.solve();
	return 0;
}
posted @ 2019-03-04 16:42  Hyscere  阅读(144)  评论(0编辑  收藏  举报