【LOJ6070】「2017 山东一轮集训 Day4」基因(回文自动机)(主席树)

传送门


题解:

其实和BZOJ5384是同一个东西,只需要把区间加用主席树维护一下就行了。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const

namespace IO{
	inline char get_char(){
		static cs int Rlen=1<<22|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	template<typename T>
	inline T get(){
		char c;
		while(!isdigit(c=gc()));T num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
	inline int getint(){return get<int>();}
}
using namespace IO;

using std::cerr;
using std::cout;

cs int N=1e5+5;

int n,q,op;

char s[N];

namespace PAM{
	int son[N][26],fa[N],len[N],last,now;
	int up[N],d[N];
	
	int in[N],out[N],clk;
	std::vector<int> G[N];
	
	inline void init(){fa[0]=1,len[1]=-1,now=1;}
	
	inline void push_back(char c,int i){c-='a';
		int p=last;
		while(s[i]!=s[i-len[p]-1])p=fa[p];
		if(!son[p][c]){
			len[++now]=len[p]+2;
			int k=fa[p];
			while(s[i]!=s[i-len[k]-1])k=fa[k];
			fa[now]=son[k][c],son[p][c]=now;
			d[now]=len[now]-len[fa[now]];
			up[now]=d[now]==d[fa[now]]?up[fa[now]]:now;
		}
		last=son[p][c];
	}
	
	void dfs(int u){
		in[u]=++clk;
		for(int re v:G[u])dfs(v);
		out[u]=clk;
	}
	
	inline void build(){
		for(int re i=0;i<=now;++i)if(i!=1)G[fa[i]].push_back(i);
		dfs(1);
	}
}

namespace SGT{
	int a[N<<2],M;
	inline void build(int n){for(M=1;M<n;M<<=1);}
	
	inline void update(int p,int v){
		for(a[p+=M]=v,p>>=1;p;p>>=1)a[p]=std::max(a[p<<1],a[p<<1|1]);
	}
	
	inline int query(int l,int r){
		int ans=0;
		for(l+=M-1,r+=M+1;l^r^1;l>>=1,r>>=1){
			if(l&1^1)ans=std::max(ans,a[l^1]);
			if(r&1)  ans=std::max(ans,a[r^1]);
		}
		return ans;
	}
}

int rt[N];
namespace PST{
	cs int N=::N*300;
	int lc[N],rc[N],tag[N],now;
	
	inline int newnode(int u){
		int k=++now;
		if(u)lc[k]=lc[u],rc[k]=rc[u],tag[k]=tag[u];
		return k;
	}
	
	inline void add(int &rt,int l,int r,int ql,int qr){
		rt=newnode(rt);
		if(ql<=l&&r<=qr){++tag[rt];return ;}
		int mid=l+r>>1;
		if(ql<=mid)add(lc[rt],l,mid,ql,qr);
		if(mid<qr)add(rc[rt],mid+1,r,ql,qr);
	}
	
	inline int query(int rt,int l,int r,int p){
		if(l==r)return tag[rt];
		int mid=l+r>>1;
		return tag[rt]+(p<=mid?query(lc[rt],l,mid,p):query(rc[rt],mid+1,r,p));
	}
}

signed main(){
//	freopen("gene.in","r",stdin);//freopen("gene.out","w",stdout);
	scanf("%d%d%d",&op,&n,&q);
	scanf("%s",s+1);s[0]=255;PAM::init();
	for(int re i=1;i<=n;++i)PAM::push_back(s[i],i);
	PAM::build();
	int now=1;SGT::build(PAM::clk);
	for(int re i=1;i<=n;++i){
		rt[i]=rt[i-1];
		while(s[i]!=s[i-PAM::len[now]-1])now=PAM::fa[now];
		now=PAM::son[now][s[i]-'a'];
		for(int re x=now;x;x=PAM::fa[PAM::up[x]]){
			int tmp=SGT::query(PAM::in[x],PAM::out[x]);
			int l=std::max(1,tmp-PAM::len[x]+2);
			int r=i-PAM::len[PAM::up[x]]+1;
			PST::add(rt[i],1,n,l,r);
		}
		SGT::update(PAM::in[now],i);
	}
	int ans=0;
	while(q--){
		int l=getint()^(op?ans:0),r=getint()^(op?ans:0);
		cout<<(ans=PST::query(rt[r],1,n,l))<<"\n";
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值