Bzoj2555 CTSC模拟赛 SubString

2 篇文章 0 订阅

LCT+SAM

求子串出现次数=节点right大小 所以LCT动态维护节点Right集合大小

我s[i]-'A' 写成了 s[i]-'a'  wokkkkkkkkkkk


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define LL long long
using namespace std;
//by zfy =.=
const int N=1200005;
char s[3005000];
int Len,Q,mask;
void Get(int mask){
	scanf("%s",s);Len=strlen(s);
	for(int j=0;j<Len;j++){
		mask=(mask*131+j)%Len;
		swap(s[j],s[mask]);
	}
}
struct LCT{
	int tr[N][2],fa[N],tag[N],w[N],q[N],top;
	bool isroot(int x){
		return tr[fa[x]][0]!=x&&tr[fa[x]][1]!=x;
	}
	void zig(int x){
		int y=fa[x];
		tr[y][0]=tr[x][1];if(tr[x][1]) fa[tr[x][1]]=y;tr[x][1]=y;
		if(tr[fa[y]][0]==y) tr[fa[y]][0]=x;
		if(tr[fa[y]][1]==y) tr[fa[y]][1]=x;
		fa[x]=fa[y];fa[y]=x;
	}
	void zag(int x){
		int y=fa[x];
		tr[y][1]=tr[x][0];if(tr[x][0]) fa[tr[x][0]]=y;tr[x][0]=y;
		if(tr[fa[y]][0]==y) tr[fa[y]][0]=x;
		if(tr[fa[y]][1]==y) tr[fa[y]][1]=x;
		fa[x]=fa[y];fa[y]=x;
	} 
	void splay(int x){q[++top]=x;
		for(int i=x;!isroot(i);i=fa[i]) q[++top]=fa[i];
		while(top) down(q[top--]);
		while(!isroot(x)){
			int y=fa[x];
			if(isroot(y)) {
				if(tr[y][0]==x) zig(x);
				else zag(x);
			}
			else {
				if(tr[fa[y]][0]==y) {
					if(tr[y][0]==x){
						zig(y);zig(x);
					}else {
						zag(x);zig(x);
					}
				}
				else {
					if(tr[y][1]==x){
						zag(y);zag(x);
					}else {
						zig(x);zag(x);
					}
				}
			}
		}
	}	
	void access(int x){
		for(int t=0;x;t=x,x=fa[x]){
			splay(x);tr[x][1]=t;
		}
	} 
	void down(int x){
		add(tr[x][0],tag[x]);
		add(tr[x][1],tag[x]); 
		tag[x]=0;
	}
	void add(int x,int ww){
		if(!x) return;
		tag[x]+=ww;w[x]+=ww;
	}
	void link(int x,int y){
		fa[x]=y;access(y);splay(y);add(y,w[x]);
	}
	void cut(int x){
		access(x);splay(x);add(tr[x][0],-w[x]);
		fa[tr[x][0]]=0;tr[x][0]=0;
	}
}T;
struct SAM{
	int p,np,q,nq,l[N],tr[N][26],fa[N],cnt,last;
	SAM(){
		last=++cnt;
	}
	void add(int x){
		p=last;np=last=++cnt;T.w[np]=1;l[np]=l[p]+1;
		for(;p&&!tr[p][x];p=fa[p]) tr[p][x]=np;
		if(!p) {fa[np]=1;T.link(np,1);}
		else {
			q=tr[p][x];
			if(l[q]==l[p]+1) {fa[np]=q;T.link(np,q);}
			else {
				nq=++cnt;l[nq]=l[p]+1;
				memcpy(tr[nq],tr[q],sizeof tr[q]);
				fa[nq]=fa[q];T.link(nq,fa[q]);
				T.cut(q);fa[q]=fa[np]=nq;
				T.link(q,nq);T.link(np,nq);
				for(;tr[p][x]==q;p=fa[p]) tr[p][x]=nq;
			}
		}
	}
	void build(){
		scanf("%s",s);Len=strlen(s);
		for(int i=0;i<Len;i++) add(s[i]-'A');
	}
	void add(){
		Get(mask);for(int i=0;i<Len;i++) add(s[i]-'A');
	}
	int ask(){
		Get(mask);int cur=1;
		for(int i=0;i<Len;i++){
			if(tr[cur][s[i]-'A']) cur=tr[cur][s[i]-'A'];
			else return 0;
		}
		T.splay(cur);
		return T.w[cur];
	}
}S;
int main(){
	scanf("%d",&Q);S.build();
	for(int i=1;i<=Q;i++){
		scanf("%s",s);
		if(s[0]=='A') S.add();
		else {
			int res=S.ask();	
			printf("%d\n",res);
			mask^=res;
		}
	}
	return 0;
}
    /*
	
4
A
QUERY A
ADD BBABBBBAAB
QUERY A
QUERY B
	*/


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值