luogu P5212 SubString

题面传送门
写了一个晚上才写完+调完,AC那一刻感觉神清气爽。
询问某一个串在另一个串内出现了几次想到AC自动机,但是因为强制在线而AC自动机无法动态更新fail树所以考虑SAM
然后发现我们只要动态维护LCT虚子树大小即可。
然而虚子树大小其实挺难维护的,所以可以改成每个点的链加。
时间复杂度\(O(nlogn)\)
code:

#include<cstdio>
#include<cstring>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define beg(x) int cur=s.h[x]
#define end cur
#define go cur=tmp.z
#define l(x) x<<1
#define r(x) x<<1|1
#define N 6000039
#define ll long long
#define ui unsigned int
using namespace std;
int n,m,k,mask,now;char a[N],_s[N];
struct linkcuttree{
	int fa[N],l[N],r[N],flag[N],st[N],sh,f[N],g[N],now,i;
	I void swap(int &x,int &y){x^=y^=x^=y;}
	I void pushr(int x){x&&(swap(l[x],r[x]),flag[x]^=1);}
	I void pushf(int x,int y){x&&(f[x]+=y,g[x]+=y);}
	I void pushdown(int x){flag[x]&&(pushr(l[x]),pushr(r[x]),flag[x]=0);g[x]&&(pushf(l[x],g[x]),pushf(r[x],g[x]),g[x]=0);}
	I int child(int x){return l[fa[x]]==x||r[fa[x]]==x;}
	I int wrt(int x){return l[fa[x]]==x;}
	I void rotate(int x){
		int y=fa[x],z=fa[y],b=(x^l[y]?l[x]:r[x]);child(y)&&((y^l[z]?r[z]:l[z])=x);
		x^l[y]?(l[x]=y,r[y]=b):(r[x]=y,l[y]=b);fa[x]=z;fa[y]=x;b&&(fa[b]=y);
	}
	I void splay(int x){
		int y=x;st[sh=1]=x;while(child(y)) st[++sh]=y=fa[y];while(sh) pushdown(st[sh--]);
		while(child(x)) child(fa[x])&&(rotate(wrt(x)^wrt(fa[x])?x:fa[x]),0),rotate(x);
	}
	I void access(int x){for(int y=0;x;x=fa[y=x]) splay(x),r[x]=y;}
	I void makeroot(int x){access(x);splay(x);pushr(x);}
	I void link(int x,int y){makeroot(x);fa[x]=y;}
	I void split(int x,int y){makeroot(y);access(x);splay(x);}
	I void cut(int x,int y){split(x,y);pushdown(x);l[x]=fa[y]=0;}
	I void dfs(int x){if(!x) return;pushdown(x);dfs(l[x]);dfs(r[x]);}
}s;
struct SAM{
	int fa[N],len[N],son[N][2],cnt=1,last=1,now,p,cur,pus,w[N];
	I void makefa(int x,int y){fa[x]&&(s.cut(x,fa[x]),0),s.link(x,y),fa[x]=y,w[x]&&(s.split(1,x),s.pushf(1,1),0);}
	I void insert(int x){
		p=last;now=last=++cnt;w[now]=1;len[now]=len[p]+1;while(p&&!son[p][x]) son[p][x]=now,p=fa[p];
		if(!p) return  makefa(now,1);
		cur=son[p][x];if(len[p]+1==len[cur]) makefa(now,cur);
		else{
			len[pus=++cnt]=len[p]+1;makefa(pus,fa[cur]);memcpy(son[pus],son[cur],sizeof(son[pus]));
			makefa(now,pus);int t=w[cur];w[cur]=0;makefa(cur,pus);w[cur]=t;s.f[pus]+=s.f[cur];while(p&&son[p][x]==cur) son[p][x]=pus,p=fa[p];
		}
	}
}gs;
I void make(char *s){char t;now=mask;for(int i=1;i<=m;i++)now=(now*131+i-1)%m,t=s[i],s[i]=s[now+1],s[now+1]=t;}
int main(){
	freopen("1.in","r",stdin);
	freopen("1.out","w",stdout);
	register int i;
	scanf("%d",&n);scanf("%s",a+1);m=strlen(a+1);for(i=1;i<=m;i++) gs.insert(a[i]-'A');
	while(n--){
		scanf("%s",_s+1);scanf("%s",a+1);m=strlen(a+1);make(a);
		if(_s[1]=='A'){
			for(i=1;i<=m;i++)gs.insert(a[i]-'A');
		}
		else{
			now=1;for(i=1;i<=m;i++)now=gs.son[now][a[i]-'A'];
			now&&(s.access(now),s.splay(now),0);mask^=s.f[now];printf("%d\n",s.f[now]);
		}
	}
}
上一篇:关于openquery使用的一些了解


下一篇:JS 将对象拆开拼接成 URL