【BZOJ2555】Substring

题意:

给你一个字符串,要求你支持两个操作:

  • 在当前字符串的后面插入一个字符串;

  • 询问字符串s在当前字符串中出现了几次?(作为连续子串);

你必须在线支持这些操作。

题解:

SAM 入门题。

做法:后缀树某节点的子树大小即为该节点所对应的串的出现次数,相信大家都非常清楚。

那么这题就用 LCT 动态维护后缀树的子树大小即可。

LCT动态维护子树大小可以参考 【[BZOJ2014]大融合】 一题,实子树虚子树分别处理。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cassert>
using std::swap;
inline int gi()
{
	char c; int x=0;
	for(;c<'0'||c>'9';c=getchar());
	for(;c>='0'&&c<='9';c=getchar())x=(x<<1)+(x<<3)+c-'0';
	return x;
}
const int N=3000005;
int ch[N][2],fa[N],n,m,w[N],st[N],siz[N],isze[N];
bool rev[N];
int pre[N],to[N][30],len[N],cnt=1,lst=1,size[N];
char s[N];
#define isnrt(x) (ch[fa[x]][0]==x||ch[fa[x]][1]==x)
void pushup(int x) {
	siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+isze[x];
}
void pushdown(int x)
{
	if(rev[x])
	{
		rev[ch[x][0]]^=1,rev[ch[x][1]]^=1;
		swap(ch[x][0],ch[x][1]);
		rev[x]=0;
	}
}
void rotate(int x){
	int y=fa[x],z=fa[y];
	bool k=ch[y][0]==x; int w=ch[x][k];
	if(isnrt(y))ch[z][ch[z][1]==y]=x;ch[x][k]=y;ch[y][!k]=w;
	fa[w]=y;fa[y]=x;fa[x]=z;
	pushup(y); pushup(x);
}
void splay(int x)
{
	int y=x,tp=1; st[1]=y;
	while(isnrt(y)) st[++tp]=y=fa[y];
	while(tp) pushdown(st[tp--]);
	while(isnrt(x))
	{
		int y=fa[x],z=fa[y];
		if(isnrt(y)) (ch[z][1]==y)^(ch[y][1]==x)?rotate(x):rotate(y);
		rotate(x);
	}
	pushup(x); 
}
void access(int x)
{
	bool flag=false;
	int y=0;
	for(;x;y=x,x=fa[x])
	{
		splay(x);isze[x]+=siz[ch[x][1]];
		ch[x][1]=y,isze[x]-=siz[y];
		pushup(x);
	}
}
void makert(int x) {
	access(x),splay(x),rev[x]^=1;
}
void split(int x, int y) {
	makert(x),access(y),splay(y);
}
void link(int x, int y) {
	split(x,y),fa[x]=y;
	isze[y]+=siz[x],pushup(y);
}
void cut(int x) {
	access(x),splay(x);
	ch[x][0]=fa[ch[x][0]]=0,pushup(x);
}
void extend(int c)
{
	int p=lst,np=++cnt;lst=np;isze[cnt]=1;
	len[np]=len[p]+1,size[np]=1;
	for(;p&&!to[p][c];p=pre[p]) to[p][c]=np;
	if(!p) {
		link(np,1);
		pre[np]=1;
		return ;
	}
	int q=to[p][c];
	if(len[p]+1==len[q]) {
		link(np,q);
		pre[np]=q;
		return ;
	}
	int nq=++cnt;len[nq]=len[p]+1;
	memcpy(to[nq],to[q],sizeof(to[q]));
	if(pre[q]) cut(q),link(nq,pre[q]);
	pre[nq]=pre[q],pre[q]=pre[np]=nq;
	link(q,nq),link(np,nq);
	for(;to[p][c]==q;p=pre[p])to[p][c]=nq;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("2102.in","r",stdin);
	freopen("2102.out","w",stdout);
#endif
	int q,m=0;
	scanf("%d%s",&q,s);
	for(int i=0;s[i];++i) extend(s[i]-'A');
	while(q--)
	{
		char op[10]; scanf("%s%s",op,s);
		int len=strlen(s),msk=m;
		for(int i=0;s[i];++i)
		{
			msk=(msk*131+i)%len;
			swap(s[i],s[msk]);
		}
		if(op[0]=='A')
		{
			for(int i=0;s[i];++i) extend(s[i]-'A');
			continue;
		}
		int now=1;
		for(int i=0;s[i]&&now;++i) now=to[now][s[i]-'A'];
		if(!now) {
			puts("0");
			continue;
		}
		access(now),splay(now),printf("%d\n",isze[now]),m^=isze[now];
	}
}
posted @ 2019-02-27 22:43  x_faraway_x  阅读(134)  评论(0编辑  收藏  举报