LOJ3298 封印

题目传送门

分析:
对于每一个左端点\(l\),我们都能找到一个\(r\),使得\(l \leq j \leq r\)\(S_{l,j}\)\(T\)的子串,\(j \geq r\)\(S_{l,j}\)不为\(T\)的子串
\(l\)增大时,对应的\(r\)单调不降,尝试求出每一个\(l\)对应的\(r\)
考虑建一个SAM,目前的\(S_{l,r}\)对应的子串所在节点为\(p\)\(r\)加一位,相当于沿着字符转移边跳一步
如果目前节点子串集合最短长度(即父亲的\(len\)加一)大于了\(r-l+1\),则\(p\)往后缀树上的父亲跳一步
复杂度是\(O(n)\)
找到了每一个位置\(i\)对应的\(r_i\),考虑询问\(L,R\)
需要分\(r_i \leq R\)\(r_i>R\)分类讨论
我们对询问离线,两种情况分两棵线段树,单点修改区间取最大值可以简单维护

#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#include<queue>
#include<bitset>
#include<map>
#include<set>

#define maxn 400005
#define INF 0x3f3f3f3f

using namespace std;

inline int getint()
{
	int num=0,flag=1;char c;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
	return num*flag;
}

int n;
struct Sam{
	int fa,len,nxt[26];
}t[maxn];
char S[maxn],T[maxn];
int lst,tot,cnt;
int ans[maxn];
struct node{
	int l,r,op,id;
}q[maxn];
inline bool cmp(node x,node y)
{return x.r==y.r?x.op<y.op:x.r<y.r;}

inline void ins(int c)
{
	int p=lst,np=lst=++tot;
	t[np].len=t[p].len+1;
	while(p&&!t[p].nxt[c])t[p].nxt[c]=np,p=t[p].fa;
	if(!p)t[np].fa=1;
	else
	{
		int q=t[p].nxt[c];
		if(t[q].len==t[p].len+1)t[np].fa=q;
		else
		{
			int nq=++tot;
			memcpy(t[nq].nxt,t[q].nxt,sizeof t[q].nxt);
			t[nq].fa=t[q].fa,t[nq].len=t[p].len+1;
			t[q].fa=t[np].fa=nq;
			while(p&&t[p].nxt[c]==q)t[p].nxt[c]=nq,p=t[p].fa;
		}
	}
}

struct SegmentTree{
	int mx[maxn<<2];
	inline void update(int i,int l,int r,int p,int x)
	{
		if(l==r){mx[i]=x;return;}
		int mid=(l+r)>>1;
		if(p<=mid)update(i<<1,l,mid,p,x);
		else update(i<<1|1,mid+1,r,p,x);
		mx[i]=max(mx[i<<1],mx[i<<1|1]);
	}
	inline int getmx(int i,int l,int r,int ql,int qr)
	{
		if(qr<l||r<ql)return -INF;
		if(ql<=l&&r<=qr)return mx[i];
		int mid=(l+r)>>1;
		return max(getmx(i<<1,l,mid,ql,qr),getmx(i<<1|1,mid+1,r,ql,qr));
	}
}T1,T2;

int main()
{
	scanf("%s%s",S+1,T+1);lst=tot=1;
	n=strlen(T+1);
	for(int i=1;i<=n;i++)ins(T[i]-97);
	n=strlen(S+1);int r=0,p=1;
	for(int i=1;i<=n;i++)
	{
		r=max(i-1,r);
		if(r==i-1)p=1;
		while(p!=1&&t[t[p].fa].len+1>r-i+1)p=t[p].fa;
		while(r<n&&t[p].nxt[S[r+1]-97])p=t[p].nxt[S[++r]-97];
		q[++cnt]=(node){i,r,0,0};
	}
	for(int i=1;i<=n;i++)T1.update(1,1,n,i,-INF),T2.update(1,1,n,i,-i);
	int m=getint();
	for(int i=1;i<=m;i++)
	{
		int l=getint(),r=getint();
		q[++cnt]=(node){l,r,1,i};
	}
	sort(q+1,q+cnt+1,cmp);
	for(int i=1;i<=cnt;i++)
		if(!q[i].op)
		{
			T1.update(1,1,n,q[i].l,q[i].r-q[i].l+1);
			T2.update(1,1,n,q[i].l,-INF);
		}
		else ans[q[i].id]=max(T1.getmx(1,1,n,q[i].l,q[i].r),q[i].r+T2.getmx(1,1,n,q[i].l,q[i].r)+1);
	for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
}

posted @ 2020-07-07 10:45  Izayoi_Doyo  阅读(106)  评论(0编辑  收藏  举报