loj #6070. 「2017 山东一轮集训 Day4」基因

回文自动机好题啊!

解法一

每$sqrt n (分一块 每块建回文自动机到字符串末尾。 顺便开三个)sqrt n * n(的数组记下预处理答案,回文自动机头指针,和每个节点第一次出现的右端点 询问的时候回文自动机前端添加,算出答案。 貌似不能写均摊复杂度的回文自动机,只能写单次复杂度有证明的。 设)T(为字符集大小 时间复杂度)O(Tn+n sqrt n)$

#include <bits/stdc++.h>
using namespace std;
const int N=100010,D=320;
int pre[D][N],preworkans[D][N],firstappear[D][N],vis[N];
struct pam{
	struct pamnode{
		int len,fa,anc[26],trans[26];
	}T[N];
	int tot,fi,la;
	pam(){
		T[1].len=-1;
		T[0].fa=1;
		for (int j=0; j<26; ++j) T[0].anc[j]=1;
		tot=1;
		fi=0;
		la=0;
	}
	void pushback(char *s,int l,int r){
		int c=s[r]-'a';
		if (r-T[la].len-1<l||s[r]!=s[r-T[la].len-1]) la=T[la].anc[c];
		if (!T[la].trans[c]){
			int q=++tot,k=T[la].fa;
			T[q].len=T[la].len+2;
			if (r-T[k].len-1<l||s[r]!=s[r-T[k].len-1]) T[q].fa=T[T[k].anc[c]].trans[c];
			else T[q].fa=T[k].trans[c];
			memcpy(T[q].anc,T[T[q].fa].anc,sizeof(T[q].anc));
			T[q].anc[s[r-T[T[q].fa].len]-'a']=T[q].fa;
			T[la].trans[c]=q;
		}
		la=T[la].trans[c];
		if (T[la].len==r-l+1) fi=la;
	}
	void pushfront(char *s,int l,int r){
		int c=s[l]-'a';
		if (l+T[fi].len+1>r||s[l]!=s[l+T[fi].len+1]) fi=T[fi].anc[c];
		if (!T[fi].trans[c]){
			int q=++tot,k=T[fi].fa;
			T[q].len=T[fi].len+2;
			if (l+T[k].len+1>r||s[l]!=s[l+T[k].len+1]) T[q].fa=T[T[k].anc[c]].trans[c];
			else T[q].fa=T[k].trans[c];
			memcpy(T[q].anc,T[T[q].fa].anc,sizeof(T[q].anc));
			T[q].anc[s[l+T[T[q].fa].len]-'a']=T[q].fa;
			T[fi].trans[c]=q;
		}
		fi=T[fi].trans[c];
		if (T[fi].len==r-l+1) la=fi;
	}
}A;
int ty,n,q,S,clk,ans;
char s[N];
int main(){
	scanf("%d%d%d%s",&ty,&n,&q,s+1);
	S=sqrt(n);
	for (int i=0; i*S+1<=n; ++i){
		A.fi=A.la=0; ++clk;
		for (int j=i*S+1; j<=n; ++j){
			A.pushback(s,i*S+1,j);
			preworkans[i][j]=preworkans[i][j-1];
			if (vis[A.la]<clk){
				vis[A.la]=clk;
				firstappear[i][A.la]=j;
				++preworkans[i][j];
			}
			pre[i][j]=A.fi;
		}
	}
	while (q--){
		int l,r;
		scanf("%d%d",&l,&r);
		l^=(ty*ans);
		r^=(ty*ans);
		++clk;
		if ((l-1)/S==(r-1)/S){
			A.fi=A.la=0;
			ans=0;
			for (int i=l; i<=r; ++i){
				A.pushback(s,l,i);
				if (vis[A.la]<clk){
					vis[A.la]=clk;
					++ans;
				}
			}
		}
		else{
			int L=(l-1)/S+1-(l%S==1);
			A.fi=pre[L][r];
			ans=preworkans[L][r];
			for (int i=L*S; i>=l; --i){
				A.pushfront(s,i,r);
				if (vis[A.fi]<clk){
					vis[A.fi]=clk;
					if (firstappear[L][A.fi]>r||firstappear[L][A.fi]==0) ++ans;
				}
			}
		}
		cout<<ans<<'
';
	}
}

解法2

记回文自动机上一个节点的串长为(len(x)),父节点为(fa(x)),则对于回文树上一条链,从叶子到根,(len(x)-len(fa(x)))递减,且只有(log)种取值,也就是说,可以分成(log)个等差数列。
主席树维护扫描右端点时左端点的答案,一个等差数列就是一个区间加。
时间复杂度(O(nlog^2(n)))

#include <bits/stdc++.h>
using namespace std;
#define debug(x) cerr<<#x<<":"<<x<<endl
const int N=100010;
const int P=270010;
const int D=17*17*N;
struct zkw{
	int u,st[P];
	void init(int len){
		for (u=1; u<len; u<<=1); 
		--u;
	}
	void mark(int s,int t){
		//cerr<<"Mark"<<s<<" "<<t<<endl;
		for (s+=u; s; s>>=1) st[s]=max(st[s],t);
	}
	int ask(int s,int t){
		//cerr<<"ask"<<s<<" "<<t<<endl;
		int ret=0;
		for (s+=u-1,t+=u+1; s^t^1; s>>=1,t>>=1){
			if (~s&1) ret=max(ret,st[s^1]);
			if (t&1) ret=max(ret,st[t^1]);
		}
		//debug(ret);
		return ret;
	}
}seg1;
struct president{
	int ll,rr,tot;
	struct presidentnode{
		int l,r,v;
	}T[D];
	void add(int &ind,int l,int r){
		/*if (l!=13||r!=12){
		debug(l); debug(r); debug(tot);
		debug(ll); debug(rr);
		}*/	
		T[++tot]=T[ind];
		ind=tot;
		//cerr<<"CC"<<endl;
		if (ll<=l&&r<=rr) return void(++T[ind].v);
		int mid=(l+r)>>1;
		if (ll<=mid) add(T[ind].l,l,mid);
		if (mid<rr) add(T[ind].r,mid+1,r);
	}
	int ask(int ind,int l,int r){
		if (l==r) return T[ind].v;
		int mid=(l+r)>>1;
		return (ll<=mid?ask(T[ind].l,l,mid):ask(T[ind].r,mid+1,r))+T[ind].v;
	}
}seg2;
struct pam{
	vector<int> g[N];
	struct pamnode{
		int fa,len,d,df,trans[26];
	}T[N];
	int la,tot,dfn[N],clk,lst[N];
	pam(){
		T[1].len=-1;
		T[0].fa=1;
		T[0].d=-1;
		tot=1;
		la=0;
	}
	int pushback(char *s,int l,int r){
		int c=s[r]-'a';
		while (r-T[la].len-1<l||s[r]!=s[r-T[la].len-1]) la=T[la].fa;
		if (!T[la].trans[c]){
			int q=++tot,k=T[la].fa;
			T[q].len=T[la].len+2;
			while (r-T[k].len-1<l||s[r]!=s[r-T[k].len-1]) k=T[k].fa;
			T[q].fa=T[k].trans[c];
			T[la].trans[c]=q;
			T[q].d=(T[q].fa?T[q].len-T[T[q].fa].len:0);
			T[q].df=(T[q].d==T[T[q].fa].d?T[T[q].fa].df:q);
		}
		return la=T[la].trans[c];
	}
	void dfs(int x){
		//debug(x); debug(fa);
		dfn[x]=clk++;
		for (auto i:g[x]) dfs(i);
		lst[x]=clk-1;
	}
	void prework(){
		for (int i=tot; i>1; --i) g[T[i].fa].push_back(i);
		dfs(0);
	}
}A;
int ty,n,q,ans,rt[N],rec[N];
char s[N];
void build(){
	//for (int i=1; i<=A.tot; ++i) debug(A.dfn[i]);
	seg1.init(A.tot);
	for (int i=1; i<=n; ++i){
		rt[i]=rt[i-1];
		int x=rec[i];
		while (x>1){
			seg2.ll=max(seg1.ask(A.dfn[x],A.lst[x])-A.T[x].len+2,1);
			seg2.rr=i-A.T[A.T[x].df].len+1;
			//cerr<<"plus"<<i<<" "<<seg2.ll<<" "<<seg2.rr<<" "<<A.T[x].df<<" "<<A.T[x].len<<endl;
			seg2.add(rt[i],1,n);
			x=A.T[A.T[x].df].fa;
		}
		seg1.mark(A.dfn[rec[i]],i);
	}
}
int main(){
	scanf("%d%d%d%s",&ty,&n,&q,s+1);
	for (int i=1; i<=n; ++i) rec[i]=A.pushback(s,1,i)/*,debug(rec[i]),debug(A.T[rec[i]].fa)*/;
	A.prework();
	build();
	while (q--){
		int l,r;
		scanf("%d%d",&l,&r);
		l^=(ty*ans);
		r^=(ty*ans);
		seg2.ll=l;
		cout<<(ans=seg2.ask(rt[r],1,n))<<'
';
	}
}