BZOJ2555: SubString

题解:  建出SAM 用LCT维护Right集合即可

#include <bits/stdc++.h>
const int MAXN=3e6+10;
using namespace std;
int key[MAXN],dis[MAXN],ch[MAXN][2],chl[MAXN][26],fa[MAXN];
int pre[MAXN],sum[MAXN],sumx[MAXN];//sum xu sumx all
bool rt[MAXN];
int cnt,cur,root,mask;
char s1[MAXN],s2[MAXN];
void up(int x){sumx[x]=sumx[ch[x][0]]+sumx[ch[x][1]]+sum[x]+key[x];}
void Treavel(int x)
{
    if(x)
    {
        Treavel(ch[x][0]);
        printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d key=%2d,sum=%2d,sumx=%2d\n",x,ch[x][0],ch[x][1],pre[x],key[x],sum[x],sumx[x]);
        Treavel(ch[x][1]);
    }
}
void debug(int rp)
{
    printf("root:%d\n",rp);
    Treavel(rp);
}
void read(int t)
{
    scanf("%s",s2);
    int i,l = strlen(s2);
    for(i = 0 ; i < l ; i ++ ) t=(t*131+i)%l,swap(s2[i],s2[t]);
}
void newnode(int x,int vul){
	key[x]=sumx[x]=vul;sum[x]=0;rt[x]=1;ch[x][0]=ch[x][1]=0;pre[x]=0;
}
void rotate(int x,int kind){
	int y=pre[x];
	ch[y][!kind]=ch[x][kind];pre[ch[x][kind]]=y;
	if(rt[y])rt[x]=1,rt[y]=0;
	else ch[pre[y]][ch[pre[y]][1]==y]=x;
	pre[x]=pre[y];ch[x][kind]=y;pre[y]=x;
	up(y);
}
void splay(int x){
	while(!rt[x]){
		if(rt[pre[x]])rotate(x,ch[pre[x]][0]==x);
		else{
			int y=pre[x];int kind=ch[pre[y]][0]==y;
			if(ch[y][kind]==x)rotate(x,!kind),rotate(x,kind);
			else rotate(y,kind),rotate(x,kind);
		}
	}
	up(x);
}
void access(int x){
	int y=0;
	while(x){
		splay(x);
		if(ch[x][1])pre[ch[x][1]]=x,rt[ch[x][1]]=1,sum[x]+=sumx[ch[x][1]];
		if(y)rt[y]=0,sum[x]-=sumx[y];
		ch[x][1]=y;up(x);
		y=x;x=pre[x];
	}
}
void Link(int u,int v){
	access(u);splay(u);
	access(v);splay(v);
	pre[u]=v;sum[v]+=sumx[u];up(v);
}
void destory(int u,int v){
	access(u);splay(v);
	ch[v][1]=0;pre[u]=0;rt[u]=1;up(v);
}

int querty(int x){
	access(x);splay(x);
	return sumx[x]-sumx[ch[x][0]];
}
void built(int x,int id){
	int last=cur;cur=++cnt;int p=last;dis[cur]=id;newnode(cur,1);
	for(;p&&!chl[p][x];p=fa[p])chl[p][x]=cur;
	if(!p)fa[cur]=root,Link(cur,root);
	else{
		int q=chl[p][x];
		if(dis[q]==dis[p]+1)fa[cur]=q,Link(cur,q);
		else{
			int nt=++cnt;dis[nt]=dis[p]+1;newnode(cnt,0);
			memcpy(chl[nt],chl[q],sizeof(chl[q]));
			destory(q,fa[q]);
			fa[nt]=fa[q];Link(nt,fa[q]);fa[q]=fa[cur]=nt;Link(q,nt);Link(cur,nt);
			for(;chl[p][x]==q;p=fa[p])chl[p][x]=nt;
		}
	}
}
int slove(){
	read(mask);int temp=root;int len=strlen(s2);
	for(int i=0;i<len;i++){
		int t=s2[i]-'A';
		if(!chl[temp][t])return 0;
		temp=chl[temp][t];
	}
	int res=querty(temp);mask=mask^res;
	return res;
}
char str[11];
int main(){
	int n;scanf("%d",&n);cur=root=cnt=1;newnode(root,0);
	scanf("%s",s1+1);int len=strlen(s1+1);
	for(int i=1;i<=len;i++)built(s1[i]-'A',i);
	mask=0;int num=len;
	for(int i=1;i<=n;i++){
		scanf("%s",str);
		if(str[0]=='Q')printf("%d\n",slove());
		else{
			read(mask);len=strlen(s2);
			for(int j=0;j<len;j++)num++,built(s2[j]-'A',num);
		}
	}
}

 

2555: SubString

Time Limit: 30 Sec  Memory Limit: 512 MB
Submit: 4356  Solved: 1339
[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=maskxorResult
插入的时候,将TrueStr插到当前字符串后面即可。
HINT:ADD和QUERY操作的字符串都需要解压
长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000
新加数据一组--2015.05.20

Output

Sample Input

2
A
QUERY B
ADD BBABBBBAAB

Sample Output

0
posted @ 2018-08-29 00:39  wang9897  阅读(143)  评论(0编辑  收藏  举报