把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【BZOJ2555】SubString(后缀自动机+LCT)

点此看题面

大致题意: 给你一个初始字符串,让你支持两种操作:在它后面接入一个字符串;询问一个字符串出现次数。(强制在线)

前言

毒瘤题。。。

没怎么写过\(LCT\)维护子树信息,有个地方是自己yy的,结果挂了调得想死。。。

后缀自动机

看到这种字符串题目,显然可以上后缀自动机。

强制在线接入一个字符串,使用后缀自动机似乎没多大问题。而一个字符串的出现次数,只要找到对应节点,该节点的\(Sz\)即为答案。

看着好像一点问题都没有,但是。。。

我们该如何维护\(Sz\)呢?

\(LCT\)

我们暂时不管后缀自动机,而是单独去考虑它的\(parent\)树,则\(Sz\)其实就是一个子树的大小。

然后想想我们都对\(parent\)树干了些什么:加点、删边、连边,这不就是个\(LCT\)嘛!

等等,你说\(LCT\)怎么维护子树信息?可以去看看这道题:【洛谷4219】[BJOI2014] 大融合(题解坑掉懒得去补了,因此给的是题目链接)。

于是这道题就做完了。

是的,做完了,代码也就七十几行,只是细节有点多而已。。。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 600000
using namespace std;
int n;char op[10],s[N+5];
class LinkCutTree//LCT
{
	private:
		#define PU(x) (O[x].Sz=O[x].ISz+O[O[x].S[0]].Sz+O[O[x].S[1]].Sz+O[x].T)
		#define IR(x) (O[O[x].F].S[0]^x&&O[O[x].F].S[1]^x)
		#define Wh(x) (O[O[x].F].S[1]==x)
		#define Co(x,y,d) (O[O[x].F=y].S[d]=x)
		#define PD(x) O[x].R&&(Re(O[x].S[0]),Re(O[x].S[1]),O[x].R=0)
		#define Re(x) (swap(O[x].S[0],O[x].S[1]),O[x].R^=1)
		#define MR(x) (Ac(x),S(x),Re(x))
		int St[N<<1];struct node {int T,Sz,ISz,R,F,S[2];}O[N<<1];
		I void Ro(RI x)
		{
			RI f=O[x].F,p=O[f].F,d=Wh(x);!IR(f)&&(O[p].S[Wh(f)]=x),
			O[x].F=p,Co(O[x].S[d^1],f,d),Co(f,x,d^1),PU(f),PU(x);
		}
		I void S(RI x)
		{
			RI f=x,T=0;W(St[++T]=f,!IR(f)) f=O[f].F;W(T) PD(St[T]),--T;
			W(!IR(x)) f=O[x].F,!IR(f)&&(Ro(Wh(x)^Wh(f)?x:f),0),Ro(x);
		}
		I void Ac(RI x)
		{
			for(RI y=0;x;x=O[y=x].F) S(x),
				O[x].ISz+=O[O[x].S[1]].Sz-O[y].Sz,O[x].S[1]=y,PU(x);//注意更新虚儿子信息
		}
	public:
		I void Init(CI x) {O[x].Sz=O[x].T=1;}
		I void Link(CI x,CI y) {MR(x),MR(y),O[O[y].F=x].ISz+=O[y].Sz,O[x].Sz+=O[y].Sz;}//连边
		I void Cut(CI x,CI y) {MR(x),Ac(y),S(x),O[x].Sz-=O[y].Sz,O[x].S[1]=O[y].F=0;}//删边
		I int Qry(CI f,CI x) {return MR(f),Ac(x),S(f),O[x].Sz;}//处理询问
}LCT;
class SuffixAutomation//后缀自动机
{
	private:
		int Nt,lst;struct node {int L,F,S[30];}O[N<<1];
	public:
		I SuffixAutomation() {Nt=lst=1;}
		I void Ins(CI x)//插入字符
		{
			RI p=lst,now=lst=++Nt;O[now].L=O[p].L+1,LCT.Init(now);
			W(p&&!O[p].S[x]) O[p].S[x]=now,p=O[p].F;if(!p) return LCT.Link(O[now].F=1,now);
			RI q=O[p].S[x];if(O[p].L+1==O[q].L) return LCT.Link(O[now].F=q,now);
			RI k=++Nt;(O[k]=O[q]).L=O[p].L+1,O[now].F=O[q].F=k,
			LCT.Cut(O[k].F,q),LCT.Link(O[k].F,k),LCT.Link(k,now),LCT.Link(k,q);
			W(p&&O[p].S[x]==q) O[p].S[x]=k,p=O[p].F;
		}
		I int Qry(char *s)//询问
		{
			RI p=1;for(RI i=1;i<=n;++i) if(!(p=O[p].S[s[i]&31])) return 0;//找到对应节点
			return LCT.Qry(O[p].F,p);//LCT上询问Sz
		}
}S;
I void T(char *s,RI p) {for(RI i=1;i<=n;++i) swap(s[i],s[(p=(p*131+i-1)%n)+1]);}//强制在线
int main()
{
	RI Qt,i;for(scanf("%d%s",&Qt,s+1),n=strlen(s+1),i=1;i<=n;++i) S.Ins(s[i]&31);//读入并处理初始串
	RI t,p=0;W(Qt--)
	{
		scanf("%s%s",op,s+1),n=strlen(s+1),T(s,p);
		if(op[0]=='Q') printf("%d\n",t=S.Qry(s)),p^=t;else for(i=1;i<=n;++i) S.Ins(s[i]&31);
	}return 0;
}
posted @ 2020-05-29 15:16  TheLostWeak  阅读(136)  评论(0编辑  收藏  举报