洛谷P5212:SubString(SAM、LCT)

解析

所谓SAM套LCT,真的就只是SAM套LCT。。。

考试写起来应该有亿点点恶心

每次在SAM节点修改的时候在LCT对应位置修改即可。

注意! 克隆节点之前需要先splay一下把所有标记接收。

没了。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
inline ll read(){
	ll x(0),f(1);char c=getchar();
	while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
const int N=3e6+100;
const int M=1e6+100;
const int mod=1e9;
int clo;

struct SAM;

struct LCT{
	int tr[N][2],f[N],val[N],rev[N],add[N];
	#define ls(o) tr[o][0]
	#define rs(o) tr[o][1]
	inline bool isroot(int x){
		return ls(f[x])!=x&&rs(f[x])!=x;
	}
	inline bool which(int x){
		return tr[f[x]][1]==x;
	}
	inline void Rev(int x){
		if(x){
			rev[x]^=1;swap(ls(x),rs(x));
		}
		return;
	}
	inline void Add(int x,int w){
		if(x){
			val[x]+=w;add[x]+=w;
		}
		return;
	}
	inline void pushdown(int x){
		if(rev[x]){
			rev[x]=0;
			Rev(ls(x));Rev(rs(x));
		}
		if(add[x]){
			int w=add[x];add[x]=0;
			Add(ls(x),w);Add(rs(x),w);
		}
		return;
	}
	inline void rotate(int x){
		int fa=f[x],gfa=f[fa];
		int d=which(x),son=tr[x][d^1];
		pushdown(gfa);pushdown(fa);pushdown(x);
		f[x]=gfa;if(!isroot(fa)) tr[gfa][which(fa)]=x;
		f[fa]=x;tr[x][d^1]=fa;
		if(son){f[son]=fa;}tr[fa][d]=son;
	}
	int zhan[N];
	inline void splay(int x){
		int y=x,top=0;
		zhan[++top]=y;
		while(!isroot(y)) zhan[++top]=y=f[y];
		while(top) pushdown(zhan[top--]);
		for(int fa;fa=f[x],!isroot(x);rotate(x)){
			if(!isroot(fa)) which(fa)==which(x)?rotate(fa):rotate(x);
		}
		return;
	}
	inline void access(int x){
		for(int y(0);x;y=x,x=f[x]){
			splay(x);
			tr[x][1]=y;
			if(y) f[y]=x;
		}
		return;
	}
	inline void makeroot(int x){
		access(x);splay(x);Rev(x);
		return;
	}
	inline int findroot(int x){
		access(x);splay(x);
		while(pushdown(x),tr[x][0]) x=tr[x][0];
		return x;
	}
	inline void split(int x,int y){
		makeroot(x);access(y);splay(y);
		return;
	}
	inline void link(int x,int y){
		//printf("link: %d - %d\n",x,y);
		makeroot(x);makeroot(y);
		if(findroot(x)==findroot(y)){
			assert(0);
			printf("!!\n");
			return;
		}
		f[x]=y;
	}
	inline void cut(int x,int y){
		//printf("cut: %d - %d\n",x,y);
		split(x,y);
		if(tr[y][0]!=x||tr[x][1]){
			assert(0);
			printf("??\n");
			return;
		}
		tr[y][0]=0;f[x]=0;
		return;
	}
	void newnode(int x,int f,int c=1){
		link(x,f);
		split(1,x);
		Add(x,c);
		return;
	}
	void print(int x){
		if(!x) return;
		printf("x=%d fa=%d ls=%d rs=%d val=%d rev=%d add=%d\n",
		x,f[x],ls(x),rs(x),val[x],rev[x],add[x]);
		print(ls(x));print(rs(x));
	}
	void Debug(){
		printf("---debug:\n");
		for(int i=1;i<=clo;i++){
			if(isroot(i)) print(i);
		}
		putchar('\n');
	}
}lct;

struct SAM{
	int len[N],fa[N],tr[N][2],tot,lst;
	
	SAM(){tot=lst=1;}
	
	void ins(int c){
		c-='A';		
		int cur=++tot,p=lst;lst=tot;
		len[cur]=len[p]+1;
		//printf("\n---ins: %d\n",c);
		for(;p&&!tr[p][c];p=fa[p])  tr[p][c]=cur;
		if(!tr[p][c]) fa[cur]=1;
		else{
			int q=tr[p][c];
			if(len[q]==len[p]+1) fa[cur]=q;
			else{
				int nq=++tot;
				len[nq]=len[p]+1;fa[nq]=fa[q];
				for(int i=0;i<2;i++) tr[nq][i]=tr[q][i];
				
				lct.splay(q);
				lct.val[nq]=lct.val[q];
				lct.cut(q,fa[q]);lct.link(nq,fa[q]);lct.link(q,nq);				
				
				fa[q]=fa[cur]=nq;
				for(;p&&tr[p][c]==q;p=fa[p]) tr[p][c]=nq;
				//printf("  clone(%d) = %d len=%d\n",q,nq,len[nq]);
			}
		}
		clo=tot;
		lct.newnode(cur,fa[cur]);
		//lct.Debug();
		return;
	}
	int work(char *s,int n){
		int now=1;
		for(int i=1;i<=n;i++){
			int c=s[i]-'A';
			//printf("now=%d c=%d tr=%d\n",now,c,tr[now][c]);
			if(!tr[now][c]){
				//printf("!");
				return 0;
			}
			now=tr[now][c];
		}
		//printf("now=%d\n",now);
		lct.splay(now);
		return lct.val[now];
	}
}sam;
int n,m;
char s[N],op[12],s0[N];
void get(int msk){
	for(int i=0;i<n;i++) s0[i]=s[i+1];
	for(int i=0;i<n;i++){
		msk=(msk*131+i)%n;
		swap(s0[i],s0[msk]);
		//printf("i=%d msk=%d\n",i,msk);
	}
	for(int i=1;i<=n;i++) s[i]=s0[i-1];
	return;
}
int msk;

signed main(){
	#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
	#endif
	m=read();
	scanf(" %s",s+1);n=strlen(s+1);
	for(int i=1;i<=n;i++){
		sam.ins(s[i]);
	}
	for(int i=1;i<=m;i++){
		//debug("%d\n",i);
		scanf(" %s %s",op+1,s+1);		
		n=strlen(s+1);
		get(msk);
		//printf("%s\n",s+1);
		if(op[1]=='A'){
			for(int j=1;j<=n;j++) sam.ins(s[j]);
		}
		else{
			int res=sam.work(s,n);
			printf("%d\n",res);
			msk^=res;
		}
	}
	return 0;
}
/*
8
AAAAAAA
Q A
Q AA
Q AAA
A BAB
Q A
Q AABB
Q AB
Q AABAB
*/



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值