bzoj 2555: SubString 后缀自动机+lct

        WC前鏼一题求平安qaq,,,rp++

        首先求出后缀自动机,然后相当于统计一个点的right集合的大小;转化为一个树动态加点和增减边的lct问题,然后就码码码就好了。

AC代码如下:

#include<bits/stdc++.h>
#define N 1200005
#define isrt(x) (c[fa[x]][0]!=x && c[fa[x]][1]!=x)
using namespace std;

int mask,tp,q[N],fa[N],c[N][2],tag[N],num[N]; char s[N];
void mdy(int x,int y){
	tag[x]+=y; num[x]+=y;
}
void pushdn(int x){
	if (tag[x]){
		mdy(c[x][0],tag[x]); mdy(c[x][1],tag[x]); tag[x]=0;
	}
}
void rotate(int x){
	int y=fa[x],z=fa[y],l=(c[y][1]==x),r=l^1;
	if (!isrt(y)) c[z][c[z][1]==y]=x;
	fa[x]=z; fa[y]=x; fa[c[x][r]]=y;
	c[y][l]=c[x][r]; c[x][r]=y;
}
void splay(int x){
	int i,y,z; q[tp=1]=x;
	for (i=x; !isrt(i); i=fa[i]) q[++tp]=fa[i];
	while (tp) pushdn(q[tp--]);
	for (; !isrt(x); rotate(x)){
		y=fa[x]; z=fa[y];
		if (!isrt(y)) rotate((c[z][0]==y ^ c[y][0]==x)?x:y);
	}
}
void acss(int x){
	int y=0;
	for (; x; y=x,x=fa[x]){
		splay(x); c[x][1]=y;
	}
}
void link(int x,int y){
	fa[x]=y; acss(x); splay(x);
}
void cut(int x,int y){
	acss(y); splay(y); fa[x]=c[y][1]=0;
}
struct sam_node{
	int tot,last,ch[N][26],fa[N],len[N];
	sam_node(){ tot=last=1; }
	void ins(int c){
		int np=++tot,p=last; len[np]=len[p]+1; last=tot;
		for (; p && !ch[p][c]; p=fa[p]) ch[p][c]=np;
		if (!p){
			fa[np]=1; link(np,1);
		} else{
			int q=ch[p][c];
			if (len[p]+1==len[q]){
				fa[np]=q; link(np,q);
			} else{
				int nq=++tot; len[nq]=len[p]+1; memcpy(ch[nq],ch[q],sizeof(ch[q]));
				splay(q); num[nq]=num[q];
				cut(q,fa[q]); fa[nq]=fa[q]; link(nq,fa[q]);
				fa[q]=fa[np]=nq; link(q,nq); link(np,nq);
				for (; p && ch[p][c]==q; p=fa[p]) ch[p][c]=nq;
			}
		}
		acss(np); splay(np); mdy(np,1);
	}
	void qry(){
		int now=1,len=strlen(s),i;
		for (i=0; i<len; i++) now=ch[now][s[i]-'A'];
		if (!now){ puts("0"); return; }
		splay(now); printf("%d\n",num[now]); mask^=num[now];
	}
}sam;
void pwk(int mask){
	int i,len=strlen(s);
	for (i=0; i<len; i++){
		mask=(mask*131+i)%len; swap(s[i],s[mask]);
	}
}
int main(){
	int cas,i; scanf("%d",&cas);
	scanf("%s",s);
	int len=strlen(s); char ch[10];
	for (i=0; i<len; i++) sam.ins(s[i]-'A');
	while (cas--){
		scanf("%s%s",ch,s); pwk(mask);
		if (ch[0]=='A'){
			len=strlen(s);
			for (i=0; i<len; i++) sam.ins(s[i]-'A');
		} else sam.qry();
	}
	return 0;
}


by lych

2017.2.7

©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值