【SAM】【LCT】【bzoj2555】substring

【题目描述】
给定一个字符串 A,要求在线支持以下两种操作
opt=A 在字符串A后面添加一个字符串
opt=Q 给定一个字符串 B ,求 B 在 A 中的出现次数。

【思路】

我们可以把B放到A的sam上走,答案即形成的路径的终点的right集合大小。所以问题变成了在线求right集合大小。可考虑新增一个节点,它会对parent-tree一整条链有1的贡献。所以用LCT维护parent-tree,支持链加即可。
代码:

#include<bits/stdc++.h>
#define re register
using namespace std;
const int N=2e6+5;
inline int red(){
    int data=0;bool w=0;char ch=getchar();
    while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
    if(ch=='-') w=1,ch=getchar();
    while(ch>='0' && ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
    return w?-data:data;
}
int n,m,a,b,c,mask=0;
char s[N];
void key(int mask){
	scanf("%s",s);int len=strlen(s);
	for(int re i=0;i<len;++i)
		mask=(mask*131+i)%len,swap(s[i],s[mask]);
}
namespace LCT{
	int ch[N][2],fa[N],tag[N],cnt[N],st[N],top=0;
	inline bool isroot(int x){return x!=ch[fa[x]][0]&&x!=ch[fa[x]][1];}
	inline bool get(int x){return x==ch[fa[x]][1];}
	inline void pushnow(int x,int v){if(!x)return;cnt[x]+=v;tag[x]+=v;}
	inline void pushdown(int x){
		if(!tag[x])return;
		pushnow(ch[x][0],tag[x]);
		pushnow(ch[x][1],tag[x]);
		tag[x]=0;
	}
	void rotate(int x){
		int y=fa[x],z=fa[y],d=get(x);
		if(!isroot(y))ch[z][get(y)]=x;
		fa[x]=z;fa[y]=x;ch[y][d]=ch[x][d^1];
		if(ch[y][d])fa[ch[y][d]]=y;
		ch[x][d^1]=y;
	}
	void splay(int x){
		st[top=1]=x;
		for(int re i=x;!isroot(i);i=fa[i])st[++top]=fa[i];
		while(top)pushdown(st[top--]);
		for(int re y=fa[x];!isroot(x);rotate(x),y=fa[x])
			if(!isroot(y))rotate(get(x)==get(y)?y:x);
	}
	inline void access(int x){
		int y=0;
		for(;x;x=fa[y=x])splay(x),ch[x][1]=y;
		pushnow(y,1);
	}
	inline void link(int x,int y){splay(x);fa[x]=y;}
	inline int query(int x){return splay(x),cnt[x];}
}
namespace SAM{
	map<char,int>ch[N];
	int link[N],len[N],sz=1,last=1;
	inline void insert(char c){
		int cur=++sz,p=last;
		len[cur]=len[p]+1;last=cur;
		for(;p&&!ch[p][c];p=link[p])ch[p][c]=cur;
		if(!p)return LCT::link(cur,link[cur]=1),LCT::access(cur);
		int q=ch[p][c];
		if(len[q]==len[p]+1)return LCT::link(cur,link[cur]=q),LCT::access(cur);
		else{
			int clo=++sz;
			len[clo]=len[p]+1;ch[clo]=ch[q];
			LCT::cnt[clo]=LCT::query(q);
			LCT::link(clo,link[clo]=link[q]);
			LCT::link(cur,link[cur]=clo);
			LCT::access(cur);
			LCT::link(q,link[q]=clo);
			for(;p&&ch[p][c]==q;p=link[p])ch[p][c]=clo;
		}
	}
}
int main(){
	m=red();scanf("%s",s);int len=strlen(s);
	for(int re i=0;i<len;i++)SAM::insert(s[i]);
	while(m--){
		scanf("%s",s);
		if(s[0]=='A'){
			key(mask);int len=strlen(s);
			for(int re i=0;i<len;++i)SAM::insert(s[i]);
		}else{
			key(mask);int len=strlen(s),u=1,ans;
			for(int re i=0;i<len;++i)u=SAM::ch[u][s[i]];
			if(!u)ans=0;else ans=LCT::query(u);
			cout<<ans<<"\n";mask^=ans;
		}
	}
}
发布了106 篇原创文章 · 获赞 22 · 访问量 5479

猜你喜欢

转载自blog.csdn.net/weixin_44111457/article/details/102773533