140142

ww(笑)

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;
}



阅读更多
文章标签: bzoj 后缀自动机 LCT
所属专栏: OIer刷题记录
上一篇bzoj-2780 Sevenk Love Oimaster
下一篇bzoj-1941 Hide and Seek
想对作者说点什么? 我来说一句

oracle中 substring函数的使用

2013年06月21日 1KB 下载

java中截取带汉字的字符串

2011年07月04日 1KB 下载

截取文件的文件名

2011年10月16日 1KB 下载

分类统计三种单据数量

2013年06月27日 2KB 下载

substring用法简介

2012年04月16日 16KB 下载

substring应用

2013年03月22日 869B 下载

类似subString

2012年02月17日 791B 下载

没有更多推荐了,返回首页

关闭
关闭