loading

P4482 [BJWC2018] Border 的四种求法

题意

给定字符串 \(s\)\(q\) 次询问 \(s[l,r]\) 的 border。

\(n,q\le 2\times10^5\)

题意

这里介绍的是 SAM+树剖的双 log 做法。

假设 \(s[l,r]\) 的 border 是 \(s[l,x]\),则其一定满足 \(s[l,x]=s[r-x+l,r]\),从而得到 \(\text{LCS}(s[1,x],s[1,r])\ge x-l+1\)

\(s\) 串建一个 SAM,根据 SAM 经典结论,两个串的 LCS 是 parent 树上的 LCA 的最长串。由于两个串都是前缀,其代表的点非常好找。如果 parent 树的最大深度足够小,那么我们可以枚举这个 LCA 然后 dfn 序转化成求区间 \(x\) 最大值。在一般情况下,这个做法显然平方,考虑对 parent 树树剖,转化为了 \(O(\log n)\) 段重链的前缀。下面的“重链末尾”均指的是查询的重链前缀的末端元素。

对于每条重链的非末尾元素,考虑将 \(O(n\log n)\) 个关于重链前缀的查询离线,将限制式子移项变成 \(x-\text{LCS}(s[1,x],s[1,r])+1\le l\),并令 \(b_x=x-\text{LCS}(s[1,x],s[1,r])\),开一棵线段树维护 \(b_i\) 的最大值,而由于每个 \(x\) 只会插入 \(O(\log n)\) 次(因为只有轻边才会造成一次插入),所以暴力插入复杂度正确。查询只需要在 \([l,r]\) 范围内线段树二分找到最大的 \(i\) 满足 \(b_i<l\) 即可。

对于每条重链的前缀末尾元素,考虑轻重儿子分开考虑,先将轻儿子的贡献加进去,然后删掉那个连接重链末尾的轻儿子,再统计贡献。对于重儿子,直接倒着枚举重链即可。都是只需要单点插入、单点删除。

然后还要处理一下两个点有祖先关系的答案,此时做祖先的点代表的前缀是那个点代表的等价类内的最长串(因为是前缀了,往前面添加字符必然导致 endpos 改变),所以以 \(len\) 作为 LCS 长度并无问题。实际上这种情况可以和前面几种情况放一块写,具体见代码。

总时间复杂度 \(O(n\log^2 n)\)

代码中 q1,q2,q3 分别代表了重链前缀上和重链前缀的轻儿子的查询、重链末尾的轻儿子查询、重链末尾的重链查询,v1,v2,v3 分别代表了作为轻儿子的贡献、作为重链前缀上的点的贡献和作为重链末尾后面的元素的贡献。

点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<map>
#include<unordered_map>
#include<vector>
#include<queue>
#include<stack>
#include<bitset>
#include<set>
#include<array>
#include<tuple>
#include<ctime>
#include<random>
#include<cassert>
#include<chrono>
#define x1 xx1
#define y1 yy1
#define IOS ios::sync_with_stdio(false)
#define ITIE cin.tie(0)
#define OTIE cout.tie(0)
#define PY puts("Yes")
#define PN puts("No")
#define PW puts("-1")
#define P0 puts("0")
#define P__ puts("")
#define PU puts("--------------------")
#define mp make_pair
#define fi first
#define se second
#define gc getchar
#define pc putchar
#define pb emplace_back
#define un using namespace
#define il inline
#define all(x) x.begin(),x.end()
#define mem(x,y) memset(x,y,sizeof x)
#define popc __builtin_popcountll
#define rep(a,b,c) for(int a=(b);a<=(c);++a)
#define per(a,b,c) for(int a=(b);a>=(c);--a)
#define reprange(a,b,c,d) for(int a=(b);a<=(c);a+=(d))
#define perrange(a,b,c,d) for(int a=(b);a>=(c);a-=(d))
#define graph(i,j,k,l) for(int i=k[j];i;i=l[i].nxt)
#define lowbit(x) ((x)&-(x))
#define lson(x) ((x)<<1)
#define rson(x) ((x)<<1|1)
//#define double long double
//#define int long long
//#define int __int128
using namespace std;
using i64=long long;
using u64=unsigned long long;
using pii=pair<int,int>;
template<typename T1,typename T2>inline void ckmx(T1 &x,T2 y){x=x>y?x:y;}
template<typename T1,typename T2>inline void ckmn(T1 &x,T2 y){x=x<y?x:y;}
inline auto rd(){
	int qwqx=0,qwqf=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')qwqf=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){qwqx=(qwqx<<1)+(qwqx<<3)+ch-48;ch=getchar();}return qwqx*qwqf;
}
template<typename T>inline void write(T qwqx,char ch='\n'){
	if(qwqx<0){qwqx=-qwqx;putchar('-');}
	int qwqy=0;static char qwqz[40];
	while(qwqx||!qwqy){qwqz[qwqy++]=qwqx%10+48;qwqx/=10;}
	while(qwqy--){putchar(qwqz[qwqy]);}if(ch)putchar(ch);
}
bool Mbg;
const int mod=998244353;
template<typename T1,typename T2>inline void adder(T1 &x,T2 y){x+=y,x=x>=mod?x-mod:x;}
template<typename T1,typename T2>inline void suber(T1 &x,T2 y){x-=y,x=x<0?x+mod:x;}
const int maxn=4e5+5,inf=0x3f3f3f3f;
const long long llinf=0x3f3f3f3f3f3f3f3f;
int n,Q;
struct query{
	int l,r;
}q[maxn];
int ans[maxn];
char s[maxn];
vector<int>G[maxn];
int nxt[maxn][26],fa[maxn],len[maxn];
int cur,tot;
void ins(int ch){
	int x=cur;cur=++tot,len[cur]=len[x]+1;
	while(x&&!nxt[x][ch])nxt[x][ch]=cur,x=fa[x];
	if(!x)return fa[cur]=1,void();
	int y=nxt[x][ch];
	if(len[y]==len[x]+1)return fa[cur]=y,void();
	int z=++tot;
	len[z]=len[x]+1,fa[z]=fa[y],fa[y]=fa[cur]=z,memcpy(nxt[z],nxt[y],sizeof nxt[y]);
	while(x&&nxt[x][ch]==y)nxt[x][ch]=z,x=fa[x];
}
int dep[maxn],son[maxn],siz[maxn];
void dfs1(int x){
	siz[x]=1;
	for(int u:G[x]){
		dep[u]=dep[x]+1,dfs1(u),siz[x]+=siz[u];
		if(!son[x]||siz[u]>siz[son[x]])son[x]=u;
	}
}
int tp[maxn];
//重链 
vector<int>vec[maxn];
void dfs2(int x,int rt){
	tp[x]=rt,vec[rt].pb(x);
	if(son[x])dfs2(son[x],rt);
	for(int u:G[x])if(u^son[x])dfs2(u,u);
}
//在点fa[i]的轻儿子i中插入前缀p 
vector<pii>v[maxn],v3[maxn];
vector<int>v2[maxn];
/*
q1 lca 是重链前缀
q2 lca 是重链末尾 
*/
vector<int>q1[maxn],q2[maxn],q3[maxn];
int pt[maxn];
namespace sgt{
	int d[maxn<<2];
	#define mid ((l+r)>>1)
	il void pu(int p){
		d[p]=min(d[lson(p)],d[rson(p)]);
	}
	void bd(int l=1,int r=n,int p=1){
		d[p]=inf;
		if(l==r)return;
		bd(l,mid,lson(p)),bd(mid+1,r,rson(p));
	}
	void add(int x,int val,int l=1,int r=n,int p=1){
		if(l==r)return d[p]=val,void();
		x<=mid?add(x,val,l,mid,lson(p)):add(x,val,mid+1,r,rson(p));
		pu(p);
	}
	void del(int x,int l=1,int r=n,int p=1){
		if(l==r)return d[p]=inf,void();
		x<=mid?del(x,l,mid,lson(p)):del(x,mid+1,r,rson(p));
		pu(p);
	}
	vector<array<int,3>>arr;
	void get(int ll,int rr,int l=1,int r=n,int p=1){
		if(ll<=l&&r<=rr)return arr.push_back({l,r,p});
		if(ll<=mid)get(ll,rr,l,mid,lson(p));
		if(rr>mid)get(ll,rr,mid+1,r,rson(p));
	}
	int fnd(int v,int l,int r,int p){
		if(l==r)return l;
		if(d[rson(p)]<v)return fnd(v,mid+1,r,rson(p));
		return fnd(v,l,mid,lson(p));
	}
	int qry(int l,int r,int v){
		if(l>r)return -1;
		arr.clear(),get(l,r);
		reverse(all(arr));
		for(auto i:arr)if(d[i[2]]<v)return fnd(v,i[0],i[1],i[2]);
		return -1;
	}
	#undef mid
}un sgt;
inline void solve_the_problem(){
	scanf("%s",s+1),n=strlen(s+1),Q=rd();
	cur=tot=1,fa[1]=0,len[1]=0;
	rep(i,1,n)ins(s[i]-'a');
	int P=1;
	rep(i,1,n)P=nxt[P][s[i]-'a'],pt[i]=P;
//	rep(i,1,n)write(pt[i],32);P__;
	rep(i,2,tot)G[fa[i]].pb(i);
//	rep(i,1,tot)write(len[i],32);P__;
//	rep(i,2,tot)write(fa[i],32),write(i);
	dfs1(1),dfs2(1,1);
	rep(i,1,Q){
		int l=rd(),r=rd();
		q[i]=(query){l,r};
		int p=pt[r];
		q1[p].pb(i),q3[p].pb(i);
		while(tp[p]!=1){
			const int t=tp[p],ft=fa[t];
			q2[t].pb(i),q3[ft].pb(i);
			if(ft!=tp[ft])q1[fa[ft]].pb(i);
			p=ft;
		}
	}
	rep(i,1,n){
		int p=pt[i];
		v2[p].pb(i),v3[p].pb(mp(i,i-len[p]));
		while(tp[p]!=1){
			const int t=tp[p],ft=fa[t];
			v[t].pb(mp(i,i-len[ft])),p=ft;
		}
	}
	bd();
	//type 1
	rep(r,1,tot)if(tp[r]==r){
		for(int x:vec[r]){
			for(int u:G[x])if(u^son[x]){
				for(pii _:v[u]){
					int i=_.fi,val=_.se;
					add(i,val);
				}
			}
			for(pii _:v3[x]){
				int i=_.fi,val=_.se;
				add(i,val);
			}
			for(int i:q1[x]){
				int res=qry(q[i].l,q[i].r-1,q[i].l);
				if(res!=-1)ckmx(ans[i],res-q[i].l+1);
			}
		}
		for(int x:vec[r]){
			for(int u:G[x])if(u^son[x]){
				for(pii _:v[u]){
					int i=_.fi;
					del(i);
				}
			}
			for(pii _:v3[x]){
				int i=_.fi;
				del(i);
			}
		}
	}
//	write(ans[1]);
	//type 2
	rep(r,1,tot)if(tp[r]==r){
		reverse(all(vec[r]));
		for(int x:vec[r]){
			for(int u:G[x])if(u^son[x]){
				for(pii _:v[u]){
					int i=_.fi;
					add(i,i);
				}
			}
			for(int u:G[x])if(u^son[x]){
				if(q2[u].empty())continue; 
				for(pii _:v[u]){
					int i=_.fi;
					del(i);
				}
				for(int i:q2[u]){
					int res=qry(q[i].l,q[i].r-1,q[i].l+len[x]);
					if(res!=-1)ckmx(ans[i],res-q[i].l+1);
				}
				for(pii _:v[u]){
					int i=_.fi;
					add(i,i);
				}
			}
		}
		for(int x:vec[r]){
			for(int u:G[x])if(u^son[x]){
				for(pii _:v[u]){
					int i=_.fi;
					del(i);
				}
			}
			for(int i:v2[x]){
				del(i);
			}
		}
	}
	//type 3
	rep(r,1,tot)if(tp[r]==r){
		for(int x:vec[r]){
			for(int i:v2[x]){
				add(i,i);
			}
			for(int i:q3[x]){
				int res=qry(q[i].l,q[i].r-1,q[i].l+len[x]);
				if(res!=-1)ckmx(ans[i],res-q[i].l+1);
			}
		}
		for(int x:vec[r]){
			for(int i:v2[x]){
				del(i);
			}
		}
	}
	rep(i,1,Q)write(ans[i]);
}
bool Med;
signed main(){
//	freopen(".in","r",stdin);freopen(".out","w",stdout);
	fprintf(stderr,"%.3lfMB\n",(&Mbg-&Med)/1048576.0);
	int _=1;
	while(_--)solve_the_problem();
}
/*
abbabbaa
1
1 8
*/

posted @ 2025-08-01 19:48  dcytrl  阅读(18)  评论(0)    收藏  举报