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



关于JAVA中字符串函数subString()的用法

String str;str=str.substring(int beginIndex);截取掉str从首字母起长度为beginIndex的字符串,将剩余字符串赋值给str;str=str.subst...
  • programpoet
  • programpoet
  • 2007年05月18日 11:54
  • 20298

关于截取字符串substr和substring两者的区别

substr和substring两个都是截取字符串的。 两者有相同点,如果只是写一个参数,两者的作用都是一样的:就是截取字符串当前下标以后直到字符串最后的字符串片段。 例如:`var a=”abc...
  • adley_function
  • adley_function
  • 2016年08月05日 16:55
  • 5897

asp.net中substring用法

substringpublic String substring(int beginIndex)返回一个新的字符串,它是此字符串的一个子字符串。该子字符串始于指定索引处的字符,一直到此字符串末尾。例如...
  • lijuanders
  • lijuanders
  • 2009年10月20日 21:32
  • 11826

subString中英文截取问题以及方法

解决中英文字符截取的方法。
  • spring123tt
  • spring123tt
  • 2011年06月01日 18:57
  • 5262

subString用法

 substring方法返回位于 String 对象中指定位置的子字符串。strVariable.substring(start, end)"String Literal".substring(sta...
  • xw13106209
  • xw13106209
  • 2010年12月20日 16:48
  • 7213

String.subString(start,end)用法

String.subString(start,end)截取的字符串包括起点所在的字符串,不包括终点所在的字符串 例: String downloadUrl = "HTTP://10.140.22...
  • inthislife
  • inthislife
  • 2015年04月03日 15:39
  • 4426

Android String subString用法

substring(index):截取该位置(包括该位置)后所有字母 substring(beginIndex,endIndex):起始位置和结束位置总字母 参数: beginIndex...
  • Nature_Day
  • Nature_Day
  • 2014年07月04日 16:24
  • 6339

SQL Server数据库Substring函数使用方法小结

在SQL Server数据库操作中,我们常常会用到Substring函数,本文我们对Substring函数的使用方法进行了总结,并通过例子对它的使用方法加以说明。接下来就让我们来一起了解一下Subst...
  • fmup20115412
  • fmup20115412
  • 2014年04月20日 10:36
  • 1254

取子字符串的函数substring()

substring(int   index)   从第index个字开始到最后(String从0开始计数) substring(int   beginIndex,   int   endIndex...
  • huahuahailang
  • huahuahailang
  • 2012年05月09日 18:51
  • 7208

subString的用法

字符串截取,substring(int beginIndex) 返回一个新的字符串,它是此字符串的一个子字符串。 substring(int beginIndex, int endIndex) 返回...
  • u010227447
  • u010227447
  • 2014年05月12日 17:23
  • 4762
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:bzoj-2555 SubString
举报原因:
原因补充:

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