bzoj-2555 SubString

原创 2015年11月19日 22:28:58

题意:

给出一个字符串和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;
}



版权声明:

相关文章推荐

后缀自动机 + LCT 【bzoj2555】SubString

题目大意: 支持两个操作: 1、插入一串字符 2、查询一串字符在串中出现多少次。 强制在线题目分析: 维护一个动态的字符串,后缀自动机可以做。 要查询一串字符在串中出现的次数,就相当于查询...

[BZOJ2555][LCT][后缀自动机]SubString

题意给定一个初始字符串,要求支持两种操作,往字符串后加一个字符串和求一个字符串的出现次数。可以对字符串建后最自动机,那么一个子串x的出现次数就是|right(x)|, |right(x)|可以用fa...

bzoj 2555 Substring

SAM的下标我一直都是从0开始,结果带入LCT就挂了,而且蜜汁MLE,找了好久才发现,交了好多遍 /*************************************************...

【bzoj2555】SubString

*题目描述: 懒得写背景了,给你一个字符串init,要求你支持两个操作(1):在当前字符串的后面插入一个字符串(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)你必须在线支持这些操作。 ...

bzoj2555: SubString(后缀自动机+动态树)

Description        懒得写背景了,给你一个字符串init,要求你支持两个操作          (1):在当前字符串的后面插入一个字符串 &...

BZOJ 2555 Substring 后缀自动机+Link-Cut-Tree

题目大意:给定一个初始字符串,提供两种操作: 1.在这个字符串的后面连接一个字符串 2.询问某个字符串在当前串中出现了多少次 SAM大叔的自动机~~ 对于每个询问就是在后缀自动机上找到该子串所...

BZOJ2555 SubString 后缀自动机+LCT

题意:给一个串,支持 1.询问一个串在当前串中的出现次数 2.在串尾加一个字符串 强制在线 Sol: 如果没有添加操作,答案就是将给定串在SAM上跑到的最终状态的Right集合大小(到不了就...

BZOJ 2555 SubString 后缀自动机+LCT

在线向原串尾添加字符,询问字符串在原串中的出现次数。发现每次添加字符,Right集合就会沿Parent树大小+1,考虑LCT维护Parent树,以便区间修改。14.000s。。。。#include ...

BZOJ 2555: SubString 后缀自动机+LCT

后缀自动机的经典模型,查询一个字符串出现了几次,我们可以联想一下在代码中并未体现的right数组,我们很容易发现,有几个right数组就代表着这个单词出现了几次,那么我们只要设法维护出来就好了,我们可...

[bzoj2555]substring 解题报告

考虑用splay维护sa,每次比较的时候二分+hash。注意要在两端加-∞和+∞的点。 时间复杂度O((n+q)log2n+m)O((n+q)\log^2n+m)(n是数据总长度,m是询问总长度) ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)