BZOJ 2555: SubString

2555: SubString

Time Limit: 30 Sec  Memory Limit: 512 MB
Submit: 2556  Solved: 764
[Submit][Status][Discuss]

Description

  
    懒得写背景了,给你一个字符串init,要求你支持两个操作
    
    (1):在当前字符串的后面插入一个字符串
    
    (2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
    
    你必须在线支持这些操作。
    

Input

    第一行一个数Q表示操作个数
    
    第二行一个字符串表示初始字符串init
    
    接下来Q行,每行2个字符串Type,Str 
    
    Type是ADD的话表示在后面插入字符串。
    
    Type是QUERY的话表示询问某字符串在当前字符串中出现了几次。
    
    为了体现在线操作,你需要维护一个变量mask,初始值为0
   
    
    读入串Str之后,使用这个过程将之解码成真正询问的串TrueStr。
    询问的时候,对TrueStr询问后输出一行答案Result
    然后mask = mask xor Result  
    插入的时候,将TrueStr插到当前字符串后面即可。

HINT:ADD和QUERY操作的字符串都需要解压
   

Output

Sample Input

2

A

QUERY B

ADD BBABBBBAAB

Sample Output

0

HINT

 40 % 的数据字符串最终长度 <= 20000,询问次数<= 1000,询问总长度<= 10000
100 % 的数据字符串最终长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000

新加数据一组--2015.05.20

Source

Ctsc模拟赛By 洁妹

 

分析:

据说是$SAM$的裸题...

考虑每一次加入一个串就直接增量法建初后缀自动机,每一次询问就在$SAM$上去匹配,找到匹配完成的节点输出$|endpos|$,那么其实这道题的点大概就在于加入一个字符之后如何动态维护每个点的$|endpos|$,考虑加入一个字符,只会让这个字符在$fail$上到根结点的那条路径上的点的$|endpos|$加$1$,所以我们可以用$LCT$来维护每个点的权值,然后每一次要把路径权值$+1$就打个标记...

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;

const int maxn=1300000+5;

int n,mask,last=1,tail=1,Max[maxn],Min[maxn],nxt[maxn][26],fail[maxn];
int son[maxn][2],val[maxn],add[maxn],father[maxn];

char s[maxn],opt[13];

inline bool isroot(int x){
	if(father[x]==0)
		return true;
	int f=father[x];
	if(son[f][0]==x)
		return false;
	if(son[f][1]==x)
		return false;
	return true;
}

inline void pushdown(int x){
	if(add[x]){
		if(son[x][0])
			val[son[x][0]]+=add[x],add[son[x][0]]+=add[x];
		if(son[x][1])
			val[son[x][1]]+=add[x],add[son[x][1]]+=add[x];
		add[x]=0;
	}
}


inline void push(int t){
	static int stk[maxn];
	int top=0;
	stk[top++]=t;
	while(!isroot(t))
		stk[top++]=t=father[t];
	while(top) pushdown(stk[--top]);
}

inline void connect(int f,int t,int k){
	if(t) father[t]=f;
	if(f) son[f][k]=t;
}

inline void rotate(int t){
	int f=father[t];
	int g=father[f];
	int s=(son[f][1]==t);
	connect(f,son[t][!s],s);
	connect(t,f,!s);
	father[t]=g;
	if(g&&son[g][0]==f) son[g][0]=t;
	if(g&&son[g][1]==f) son[g][1]=t;
}

inline void splay(int t){
//	cout<<"splay: "<<t<<endl;
	push(t);
	while(!isroot(t)){
		int f=father[t];
		int g=father[f];
		if(isroot(f))
			rotate(t);
		else{
			bool a=(f&&son[f][1]==t);
			bool b=(g&&son[g][1]==f);
			if(a==b)
				rotate(f),rotate(t);
			else
				rotate(t),rotate(t);
		}
	}
}

inline void access(int t){
//	cout<<"access: "<<t<<endl;
	int p=0,x=t;
	while(t){
		splay(t);
		son[t][1]=p;
		p=t,t=father[t];
	}
	splay(x);
}

inline void link(int t,int f){
//	cout<<"link: "<<t<<" "<<f<<endl;
	splay(t);father[t]=f;
}

inline void cut(int t){
//	cout<<"cut: "<<t<<endl;
	access(t);int x=son[t][0];
	father[x]=son[t][0]=0;
}

inline void build(char *s){
	while(*s){
		int p=last,t=++tail,c=*s++-'A';
		Max[t]=Max[p]+1;
//		cout<<"char: "<<(char)(c+'A')<<endl;
		while(p&&!nxt[p][c])
			nxt[p][c]=t,p=fail[p];
		if(p){
			int q=nxt[p][c];
			if(Max[q]==Max[p]+1)
				fail[t]=q,Min[t]=Max[q]+1;
			else{
				int k=++tail;
				fail[k]=fail[q];
				fail[q]=fail[t]=k;
				Max[k]=Max[p]+1;
				Min[q]=Max[k]+1;
				Min[t]=Max[k]+1;
				Min[k]=Max[fail[k]]+1;
				memcpy(nxt[k],nxt[q],26*sizeof(int));
				while(p&&nxt[p][c]==q)
					nxt[p][c]=k,p=fail[p];
//				puts("hahahahahah");
				cut(q);link(k,fail[k]),link(q,k);val[k]=val[q];
			}
		}
		else
			Min[t]=fail[t]=1;
		last=t;link(t,fail[t]);
//		puts("finish link");
		access(t);
//		puts("finish access");
		add[t]++,val[t]++;
	}
}

inline void decodewithmask(int tmp){
	int len=strlen(s);
	for(int i=0;i<len;i++){
		tmp=(tmp*131+i)%len;
		swap(s[i],s[tmp]);
	}
}

inline int solve(char *s){
	int u=1;
	while(*s){
		int c=*s++-'A';
		if(nxt[u][c])
			u=nxt[u][c];
		else
			return 0;
	}
	access(u);
	return val[u];
}

signed main(void){
//	freopen("SubString1.in","r",stdin);
	scanf("%d%s",&n,s);
	build(s);
	for(int i=1,ans;i<=n;i++){
		scanf("%s%s",opt,s);decodewithmask(mask);
//		puts(s);
		if(opt[0]=='Q')
			printf("%d\n",ans=solve(s)),mask^=ans;
		else
			build(s);
	}
	return 0;
}

  


$By NeighThon$

posted @ 2017-04-20 08:40  NeighThorn  阅读(186)  评论(0编辑  收藏  举报