CF1037H Security 线段树合并 SAM

LINK:Security

求一个严格大于T的字符串 是原字符串S[L,R]的子串。

容易想到尽可能和T相同 然后再补一个尽可能小的字符即可。

出于这种思想 可以在SAM上先跑匹配 然后枚举加哪个字符 判定即可。

判定s是否在[L,R]中出现过 最快的方法 就是right集了。

这个可以线段树合并完成 注意 合并的时候 需要新建节点 防止把儿子的信息给改了。

倒着贪心即可。空间复杂度大概是nlog^2左右的注意开够。(我也不太会计算空间

const int MAXN=100010;
int n,m,id,len;
int last=1,cnt=1,top;
char a[MAXN<<1],b[MAXN<<1];
struct wy
{
	int fa,len;
	int ch[26];
}t[MAXN<<1];
int root[MAXN<<1],q[MAXN<<1],c[MAXN<<1],pre[MAXN<<1];
struct jl{int l,r,sum;}s[MAXN*200];
inline void insert(int x)
{
	int p=last;
	int np=last=++cnt;
	len(np)=len(p)+1;
	while(p&&!t[p].ch[x])
	{
		t[p].ch[x]=np;
		p=f(p);
	}
	if(!p)f(np)=1;
	else
	{
		int q=t[p].ch[x];
		if(len(p)+1==len(q))f(np)=q;
		else
		{
			int nq=++cnt;
			t[nq]=t[q];
			len(nq)=len(p)+1;
			f(np)=f(q)=nq;
			while(p&&t[p].ch[x]==q)
			{
				t[p].ch[x]=nq;
				p=f(p);
			}
		}
	}
}
inline void change(int &p,int l,int r,int x)
{
	if(!p)p=++id;
	if(l==r){++sum(p);return;}
	int mid=(l+r)>>1;
	if(x<=mid)change(l(p),l,mid,x);
	else change(r(p),mid+1,r,x);
	sum(p)=sum(l(p))+sum(r(p));
}
inline void topsort()
{
	rep(1,cnt,i)++c[len(i)];
	rep(1,cnt,i)c[i]+=c[i-1];
	rep(1,cnt,i)q[c[len(i)]--]=i;
}
inline int merge(int x,int y,int l,int r)
{
	if(!x||!y)return x|y;
	int w=++id;
	if(l==r){sum(w)=sum(x)+sum(y);return w;}
	int mid=(l+r)>>1;
	l(w)=merge(l(x),l(y),l,mid);
	r(w)=merge(r(x),r(y),mid+1,r);
	sum(w)=sum(l(w))+sum(r(w));
	return w;
}
inline int ask(int p,int l,int r,int L,int R)
{
	if(!p||L>R)return 0;
	if(L<=l&&R>=r)return sum(p);
	int mid=(l+r)>>1,ww=0;
	if(L<=mid)ww+=ask(l(p),l,mid,L,R);
	if(R>mid)ww+=ask(r(p),mid+1,r,L,R);
	return ww;
}
int main()
{
	freopen("1.in","r",stdin);
	gc(a);len=strlen(a+1);
	rep(1,len,i)insert(a[i]-'a'),change(root[last],1,len,i);
	topsort();gt(n);
	fep(cnt,2,i)root[f(q[i])]=merge(root[f(q[i])],root[q[i]],1,len);
	rep(1,n,i)
	{
		int x,y;
		gt(x);gt(y);gc(b);
		int now=1,last=-1,flag=0;top=0;
		int len1=strlen(b+1);
		rep(1,len1,j)
		{
			int cc=b[j]-'a';
			if(t[now].ch[cc])pre[t[now].ch[cc]]=now,now=t[now].ch[cc],a[++top]=b[j];
			else {last=b[j]-'a';break;}
		}
		while(now)
		{
			rep(last+1,25,j)
			{
				if(flag)break;
				int ww=t[now].ch[j];
				if(ww)
				{
					if(ask(root[ww],1,len,x+top,y))
					{
						a[++top]=j+'a';
						flag=1;
					}
				}
			}
			if(flag)break;
			now=pre[now];last=b[top]-'a';
			--top;
		}
		if(!flag){puts("-1");}
		else {rep(1,top,i)printf("%c",a[i]);puts("");}
	}
	return 0;
}
上一篇:Day62:HDU1403-Longest Common Substring-后缀自动机SAM-最长公共子串


下一篇:luogu6139 【模板】广义后缀自动机(广义SAM)