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
#include
#include
#include
#include
#include
#include
#include
#include

#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>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>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

你可能感兴趣的:(LOJ3298 封印)