bzoj-2555 SubString

題意:

給出一個字符串和m次操作;

每次有兩種操作,"ADD"在串後面再加入一個串,"QUERY"查詢詢問串在整個字符串出現了多少次;

強制在線;


題解:

考慮對原串構建後綴自動機,並利用其爲增量法構建的原理維護"ADD"操作;

然後因爲這是一個自動機,所以它可以用來識別原串所有的後綴,當識別未完成時,得到的就是一個子串;

那麼當延trans指針走了自動機上的某個狀態,這個狀態的right集合大小就是這個串的出現次數了;

但是right集合不能增量維護,如果直接每次在鏈上做修改那個複雜度是錯的;

所以我們可以用一個數據結構來維護這個修改,那就是LCT了!

雖說如此,LCT不能直接用來維護子樹權值的和,但是每次修改造成的影響都是對祖先那一條鏈上的,這個是可以維護的;

注意在複製結點的時候也要複製right域哦;

時間複雜度O(nlogn);


代碼:


#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 610000
#define M 3100000
#define S 26
using namespace std;
char str[M],op[10];
namespace LCT
{
	#define which(x) (ch[fa[x]][1]==x)
	int fa[N<<1],ch[N<<1][2],val[N<<1],cov[N<<1];
	bool rt[N<<1],rev[N<<1];
	void reverse(int x)
	{
		swap(ch[x][0],ch[x][1]);
		rev[x]^=1;
	}
	void Pushdown(int x)
	{
		if(rev[x])
		{
			reverse(ch[x][0]);
			reverse(ch[x][1]);
			rev[x]=0;
		}
		if(cov[x])
		{
			cov[ch[x][0]]+=cov[x];
			cov[ch[x][1]]+=cov[x];
			val[ch[x][0]]+=cov[x];
			val[ch[x][1]]+=cov[x];
			cov[x]=0;
		}
	}
	void down(int x)
	{
		if(!rt[x])	down(fa[x]);
		Pushdown(x);
	}
	void Rotate(int x)
	{
		int f=fa[x];
		bool k=which(x);
		ch[f][k]=ch[x][!k];
		ch[x][!k]=f;
		if(rt[f])	rt[f]^=rt[x]^=1;
		else		ch[fa[f]][which(f)]=x;
		fa[ch[f][k]]=f;
		fa[x]=fa[f];
		fa[f]=x;
	}
	void Splay(int x)
	{
		down(x);
		while(!rt[x])
		{
			int f=fa[x];
			if(rt[f])
			{
				Rotate(x);
				break;
			}
			if(which(x)^which(f))
				Rotate(x);
			else
				Rotate(f);
		}
	}
	void access(int x)
	{
		int y=0;
		while(x)
		{
			Splay(x);
			rt[ch[x][1]]=1;
			rt[y]=0;
			ch[x][1]=y;
			y=x,x=fa[x];
		}
	}
	void Mtr(int x)
	{
		access(x);
		Splay(x);
		reverse(x);
	}
	void update(int x,int v)
	{
		Mtr(x),access(1),Splay(x);
		val[x]+=v;cov[x]+=v;
	}
	void Link(int x,int y)
	{
		Mtr(x);
		fa[x]=y;
	}
	void Cut(int x,int y)
	{
		Mtr(x),access(y),Splay(x);
		fa[ch[x][1]]=0;
		rt[ch[x][1]]=1;
		ch[x][1]=0;
	}
	int getsum(int x)
	{
		if(!x)	return 0;
		Splay(x);
		return val[x];
	}
	#undef which
}
namespace SAM
{
	int son[N<<1][S],pre[N<<1],len[N<<1];
	bool is[N<<1];
	int tot,last;
	int newnode(int v)
	{
		tot++;
		is[tot]=v;
		LCT::rt[tot]=1;
		return tot;
	}
	void init()
	{
		tot=0;
		last=newnode(0);
	}
	void replace(int x,int y)
	{
		if(pre[x])
		{
			if(is[x])
			LCT::update(x,-1);
			LCT::Cut(x,pre[x]);
		}
		LCT::Link(x,y);
		if(is[x])
			LCT::update(x,1);
		pre[x]=y;
	}
	void Insert(int x)
	{
		int p,np=newnode(1);
		len[np]=len[last]+1;
		for(p=last;p&&!son[p][x];p=pre[p])
			son[p][x]=np;
		if(!p)
			replace(np,1);
		else
		{
			int q=son[p][x];
			if(len[q]==len[p]+1)
				replace(np,q);
			else
			{
				int nq=newnode(0);
				len[nq]=len[p]+1;
				LCT::Splay(q);
				LCT::val[nq]=LCT::val[q]-is[q];
				replace(nq,pre[q]);
				memcpy(son[nq],son[q],sizeof(int)*S);
				replace(np,nq),replace(q,nq);
				for(;son[p][x]==q;p=pre[p])
					son[p][x]=nq;
			}
		}
		last=np;
	}
	int query(char *s)
	{
		int p=1;
		while(*s!='\0')
			p=son[p][*s-'A'],s++;
		return p;
	}
}
void decode(char *s,int len,int mask)
{
	for(int j=0;j<len;j++)
	{
		mask=(mask*131+j)%len;
		swap(s[j],s[mask]);
	}
}
int main()
{
	int m,len,i,j,k,mask,ans;
	scanf("%d",&m);
	scanf("%s",str);
	len=strlen(str);
	SAM::init();
	for(i=0;i<len;i++)
		SAM::Insert(str[i]-'A');
	for(i=1,mask=0;i<=m;i++)
	{
		scanf("%s%s",op,str);
		len=strlen(str);
		decode(str,len,mask);
		if(op[0]=='A')
		{
			for(j=0;j<len;j++)
				SAM::Insert(str[j]-'A');
		}
		else
		{
			ans=LCT::getsum(SAM::query(str));
			printf("%d\n",ans);
			mask^=ans;
		}
	}
	return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章