bzoj2555-SubString

题目

给出一个初始字符串\(s\),支持两种操作:

  • 在字符串后面添加一个字符串(\(s+=t\)
  • 询问一个字符串在\(s\)中出现了几次

设字符串最终长度为\(n\),询问次数为\(q\),询问字符串总长为\(m\)\(n\le 6\times 10^5, q\le 10^4, m\le 3\times 10^6\)

分析

非常简单的题目。添加字符串用后缀自动机实现,并且用link-cut tree维护后缀树,询问一个字符串出现几次的时候,现在自动机上跑到字符串对应的点\(p\)(如果没有就是无解),再在lct上查询\(p\)的子树中关键点的个数即可。不需要使用TopTree,只需要在每次加点的时候用lct更新链上的点即可。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long giant;
const int maxn=6e5+10;
const int maxl=3e6+10;
const int maxc=26;
char s[maxl];
void decode(char s[],int len,int mask) {
	for (int j=0;j<len;++j) {
		mask=(int)((giant)mask*131+j)%len;
		swap(s[mask],s[j]);
	}
}
struct LCT {
	struct node {
		int ch[2],fa,w,sum,size,tag;
		bool rev;
		node ():size(1) {}
	} t[maxn<<1];
	LCT () {t[0].size=0;}
	bool isroot(int x) {
		return !t[x].fa || t[t[x].fa].ch[rson(x)]!=x;
	}
	bool rson(int x) {
		return t[t[x].fa].ch[1]==x;
	}
	void update(int x) {
		t[x].size=t[t[x].ch[0]].size+t[t[x].ch[1]].size+1;
		t[x].sum=t[t[x].ch[0]].sum+t[t[x].ch[1]].sum+t[x].w;
	}
	void down(int x) {
		if (!isroot(x)) down(t[x].fa);
		if (t[x].tag) {
			doit(t[x].ch[0],t[x].tag);
			doit(t[x].ch[1],t[x].tag);
			t[x].tag=0;
		}
		if (t[x].rev) {
			swap(t[x].ch[0],t[x].ch[1]);
			if (t[x].ch[0]) t[t[x].ch[0]].rev^=true;
			if (t[x].ch[1]) t[t[x].ch[1]].rev^=true;
			t[x].rev=false;
		}
	}
	void rotate(int x) {
		int f=t[x].fa,d=rson(x),c=t[x].ch[d^1];
		if (c) t[c].fa=f;
		if (!isroot(f)) t[t[f].fa].ch[rson(f)]=x;
		t[x].fa=t[f].fa,t[f].fa=x,t[x].ch[d^1]=f,t[f].ch[d]=c;
		update(f);
		update(x);
	}
	void splay(int x) {
		down(x);
		while (!isroot(x)) if (isroot(t[x].fa)) rotate(x); else {
			if (rson(x)==rson(t[x].fa)) rotate(x),rotate(x); else 
			rotate(t[x].fa),rotate(x);
		}
	}
	void access(int x) {
		for (int last=0;x;x=t[last=x].fa) {
			splay(x);
			t[x].ch[1]=last;
			update(x);
		}
	}
	void makeroot(int x) {
		access(x);
		splay(x);
		t[x].rev^=true;
	}
	void link(int x,int y) {
		makeroot(x);
		//access(y);
		t[x].fa=y;
	}
	void cut(int x,int y) {
		makeroot(x);
		access(y);
		splay(y);
		t[y].ch[0]=t[x].fa=0;
		update(y);
		update(x);
	}
	int query(int x,int y) {
		makeroot(x);
		access(y);
		splay(y);
		return t[y].sum;
	}
	void doit(int x,int w) {
		t[x].w+=w;
		t[x].sum+=t[x].size*w;
		t[x].tag+=w;
	}
	void add(int x,int y,int w) {
		makeroot(x);
		access(y);
		splay(y);
		doit(y,w);
	}
} lct;
struct SAM {
	int t[maxn<<1][maxc],len[maxn<<1],link[maxn<<1],tot,last;
	SAM ():tot(1),last(1) {}
	void add(int c) {
		int nw=++tot,i;
		len[nw]=len[last]+1;
		for (i=last;i && !t[i][c];i=link[i]) t[i][c]=nw; 
		if (i) {
			int p=t[i][c];
			if (len[p]==len[i]+1) link[nw]=p; else {
				int q=++tot;
				len[q]=len[i]+1;
				memcpy(t[q],t[p],sizeof t[p]);
				for (int j=i;j && t[j][c]==p;j=link[j]) t[j][c]=q;
				int w=lct.query(p,p);
				lct.cut(link[p],p);
				lct.link(link[p],q);
				lct.link(q,p);
				lct.add(q,q,w);
				link[q]=link[p],link[p]=link[nw]=q;
			}
		} else link[nw]=1;
		lct.link(link[nw],nw);
		lct.add(1,nw,1);
		last=nw;
	}
	int run(char s[],int len) {
		int now=1;
		for (int i=0;i<len;++i) now=t[now][s[i]-'A'];
		if (!now) return 0; 
		int ret=lct.query(now,now);
		return ret;
	}
} sam;
int main() {
#ifndef ONLINE_JUDGE
	freopen("test.in","r",stdin);
#endif
	int m,mask=0;
	scanf("%d",&m);
	scanf("%s",s);
	int len=strlen(s);
	for (int i=0;i<len;++i) sam.add(s[i]-'A');
	while (m--) {
		static char ord[10];
		scanf("%s%s",ord,s);
		len=strlen(s);
		decode(s,len,mask);
		if (ord[0]=='A') for (int i=0;i<len;++i) sam.add(s[i]-'A'); else {
			int ans=sam.run(s,len);
			mask^=ans;
			printf("%d\n",ans);
		}
	}
	return 0;
}
posted @ 2017-04-17 20:21  permui  阅读(179)  评论(0编辑  收藏  举报