【bzoj2555】 SubString

http://www.lydsy.com/JudgeOnline/problem.php?id=2555 (题目链接)

题意

  给出一个初始串,维护两个操作。在原串后面加入一个字符串;询问某个字符串在原串中出现的次数。强制在线。

Solution

  对于加入操作,我们动态构造后缀自动机,每次就将添加的节点${parent}$树上到根节点的路径上的节点的${right}$集合大小全部加${1}$。树上路径区间加法,有因为这是个动态树,所以我们用${LCT}$维护${parent}$树就可以了。

细节

  坑死了,解码过程中${mask}$是不变的,只有在询问之后才会异或上答案发生改变。幸好看了${PoPoQQQ}$大爷的博客→_→

代码

// bzoj2555
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
#define RG register
#define LL long long
#define inf (1ll<<30)
#define MOD 1000000007
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;

const int maxn=600010,maxm=3000010;
char s[maxm];
int Q,mask,r[maxn<<1];

namespace LCT {
	int tr[maxn<<1][2],fa[maxn<<1],tag[maxn<<1];
	
	void pushdown(int x) {
		if (tr[fa[x]][0]==x || tr[fa[x]][1]==x) pushdown(fa[x]);
		if (tag[x]) {
			r[tr[x][0]]+=tag[x];tag[tr[x][0]]+=tag[x];
			r[tr[x][1]]+=tag[x];tag[tr[x][1]]+=tag[x];
			tag[x]=0;
		}
	}
	void rotate(int x) {
		int y=fa[x],z=fa[y],l,r;
		l=tr[y][1]==x;r=l^1;
		if (tr[z][0]==y || tr[z][1]==y) tr[z][tr[z][1]==y]=x;
		fa[x]=z;fa[y]=x;fa[tr[x][r]]=y;
		tr[y][l]=tr[x][r];tr[x][r]=y;
	}
	void splay(int x) {
		pushdown(x);
		while (tr[fa[x]][0]==x || tr[fa[x]][1]==x) {
			int y=fa[x],z=fa[y];
			if (tr[z][0]==y || tr[z][1]==y) {
				if (tr[z][0]==y ^ tr[y][0]==x) rotate(x);
				else rotate(y);
			}
			rotate(x);
		}
	}
	void access(int x) {
		for (int y=0;x;y=x,x=fa[x])
			splay(x),tr[x][1]=y;
	}
	void add(int x,int val) {
		r[x]+=val;tag[x]+=val;
	}
	void link(int x,int y) {
		access(y);splay(y);add(y,r[x]);
		fa[x]=y;
	}
	void cut(int x) {
		access(x);splay(x);add(tr[x][0],-r[x]);
		tr[x][0]=fa[tr[x][0]]=0;
	}
	int query(int x) {
		splay(x);return r[x];
	}
}
using namespace LCT;

namespace SAM {
	int Dargen,last,sz;
	int len[maxn<<1],ch[maxn<<1][26],par[maxn<<1];
	void Init() {Dargen=last=sz=1;}
	void Extend(int c) {
		int np=++sz,p=last;last=np;
		len[np]=len[p]+1;r[np]=1;
		for (;p && !ch[p][c];p=par[p]) ch[p][c]=np;
		if (!p) par[np]=Dargen,link(np,Dargen);
		else {
			int q=ch[p][c];
			if (len[p]+1==len[q]) par[np]=q,link(np,q);
			else {
				int nq=++sz;len[nq]=len[p]+1;
				memcpy(ch[nq],ch[q],sizeof(ch[q]));
				par[nq]=par[q],link(nq,par[q]);
				par[np]=par[q]=nq;
				cut(q),link(np,nq),link(q,nq);
				for (;p && ch[p][c]==q;p=par[p]) ch[p][c]=nq;
			}
		}
	}
	int match(char *r) {
		int p=Dargen,l=strlen(r);
		for (int i=0;i<l;i++) {
			if (!ch[p][r[i]-'A']) return 0;
			p=ch[p][r[i]-'A'];
		}
		return query(p);
	}
}
using namespace SAM;

void decode(char *r,int t) {
	int len=strlen(r);
	for (int j=0;j<len;j++) {
		t=(t*131+j)%len;
		swap(r[j],r[t]);
	}
}
int main() {
	scanf("%d",&Q);
	scanf("%s",s+1);
	Init();
	int n=strlen(s+1);
	for (int i=1;i<=n;i++) Extend(s[i]-'A');
	char ch[10];mask=0;
	while (Q--) {
		scanf("%s%s",ch,s);
		decode(s,mask);
		n=strlen(s);
		if (ch[0]=='A') for (int i=0;i<n;i++) Extend(s[i]-'A');
		if (ch[0]=='Q') {
			int ans=match(s);
			mask^=ans;
			printf("%d\n",ans);
		}
	}
	return 0;
}

 

This passage is made by MashiroSky.
posted @ 2017-02-11 20:30  MashiroSky  阅读(154)  评论(0编辑  收藏  举报