Description
定义一个字符串S的权值f(S)为,其所有不同后缀两两的LCP的最大值
给出一个字符串S,每个位置有权值ai
m次询问,每次询问给出[l,r,x],求一个[l,r]的子区间[a,b],满足f(S[a,b])>=x,且max(ai)最小
n,m<=5e4
Solution
这题分成两部分
1:给出[L,R],求f(S[L,R])
考虑SAM,枚举parent树上的一个点,显然只有其right集中相邻两个有用
用set启发式合并维护right集的过程中,我们能够找出n log n个有用的三元组(l,r,len),表示S[l-len+1,l]=S[r-len+1,r]
考虑所有满足r<=R的三元组,分为两种情况:
当L<=l-len,贡献为len
当l-len+1<=L<=l,贡献为l-L
两种都可以看做区间取max单点求值,用可持久化线段树维护即可
2:我们发现区间越大,f越大
考虑询问[L,R]的答案,有三种情况:包含左端点,包含右端点,不包含左端点和右端点
前两种情况可以直接二分,考虑第三种情况,在最大值不变的情况下区间越大越好,所以只有O(n)个有用区间,预处理出每一个的f值
把询问和区间按f排序,可以用二维数据结构维护,但是有更好的方法
注意到我们二分出了最小的p,满足[L,p]是一个合法区间
考虑所有有用区间的右端点r,若r∈[L,p]则已经被考虑,若r∈[p+1,R],l>=L则有贡献,若r∈[p+1,R],l<L则不会比[L,p]优,所以直接维护右端点在[p+1,R]中的最小值即可
时空复杂度O(n log^2 n)
Code
#include <set>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
int read() {
char ch;
for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
int x=ch-'0';
for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x;
}
typedef set<int> :: iterator it;
const int N=5e4+5,M=8e6+5,inf=0x7fffffff;
int n,m,t0,a[N];
char st[N];
struct Pair{int x,y,len;}pr[N<<4];
bool cmp(Pair a,Pair b) {return a.y<b.y;}
namespace SAM{
const int N=1e5+5;
int son[N][26],len[N],fa[N],pos[N],tot,lst;
set<int> s[N];
vector<int> to[N];
int extend(int p,int x) {
int np=++tot;len[np]=len[p]+1;
for(;p&&!son[p][x];p=fa[p]) son[p][x]=np;
if (!p) fa[np]=1;
else {
int q=son[p][x];
if (len[q]==len[p]+1) fa[np]=q;
else {
int nq=++tot;
fo(i,0,25) son[nq][i]=son[q][i];
fa[nq]=fa[q];len[nq]=len[p]+1;
fa[q]=fa[np]=nq;
for(;p&&son[p][x]==q;p=fa[p]) son[p][x]=nq;
}
}
return np;
}
void dfs(int x) {
for(int z:to[x]) {
dfs(z);
if (x==1) continue;
if (s[z].size()>s[x].size()) swap(s[z],s[x]);
for(int j:s[z]) {
it k=s[x].lower_bound(j);
if (k!=s[x].end()) pr[++t0].x=j,pr[t0].y=*k,pr[t0].len=len[x];
if (k!=s[x].begin()) {
k--;
pr[++t0].x=*k,pr[t0].y=j,pr[t0].len=len[x];
}
}
for(int j:s[z]) s[x].insert(j);
}
}
void solve(char *st,int n) {
tot=lst=1;
fo(i,1,n) pos[i]=lst=extend(lst,st[i]-'a');
fo(i,1,n) s[pos[i]].insert(i);
fo(i,2,tot) to[fa[i]].push_back(i);
dfs(1);
}
}
struct Segment_Tree{
int rt[N],mx[M],ls[M],rs[M],bel[M],tot;
void modify(int &v,int l,int r,int x,int y,int z,int rt) {
if (x>y) return;
if (bel[v]!=rt) {
mx[++tot]=mx[v];bel[tot]=rt;
ls[tot]=ls[v];rs[tot]=rs[v];
v=tot;
}
if (x<=l&&r<=y) {mx[v]=max(mx[v],z);return;}
int mid=l+r>>1;
if (x<=mid) modify(ls[v],l,mid,x,y,z,rt);
if (y>mid) modify(rs[v],mid+1,r,x,y,z,rt);
}
int query(int v,int l,int r,int x) {
if (!v) return 0;
if (l==r) return mx[v];
int mid=l+r>>1,tmp=mx[v];
if (x<=mid) tmp=max(tmp,query(ls[v],l,mid,x));
else tmp=max(tmp,query(rs[v],mid+1,r,x));
return tmp;
}
}t1,t2;
int tr[N<<2];
void ins(int v,int l,int r,int x,int y) {
tr[v]=min(tr[v],y);
if (l==r) return;
int mid=l+r>>1;
if (x<=mid) ins(v<<1,l,mid,x,y);
else ins(v<<1|1,mid+1,r,x,y);
}
int que(int v,int l,int r,int x,int y) {
if (x<=l&&r<=y) return tr[v];
int mid=l+r>>1,tmp=inf;
if (x<=mid) tmp=min(tmp,que(v<<1,l,mid,x,y));
if (y>mid) tmp=min(tmp,que(v<<1|1,mid+1,r,x,y));
return tmp;
}
int F(int l,int r) {
int ret=t1.query(t1.rt[r],1,n,l),pos=t2.query(t2.rt[r],1,n,l);
return max(ret,pos-l+1);
}
int sta[N],top,L[N],R[N],an[N];
struct Que{int l,r,x,y;}ask[N],c[N];
bool cmp1(Que a,Que b) {return a.x>b.x;}
int g[N][16],lg[N];
int query(int l,int r) {
int z=lg[r-l+1];
return max(g[l][z],g[r-(1<<z)+1][z]);
}
int main() {
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
n=read();m=read();
scanf("%s",st+1);
SAM::solve(st,n);
sort(pr+1,pr+t0+1,cmp);
int j=0;
fo(i,1,n) {
t1.rt[i]=t1.rt[i-1];t2.rt[i]=t2.rt[i-1];
while (j<t0&&pr[j+1].y==i) {
j++;
t1.modify(t1.rt[i],1,n,1,pr[j].x-pr[j].len,pr[j].len,i);
t2.modify(t2.rt[i],1,n,pr[j].x-pr[j].len+1,pr[j].x,pr[j].x,i);
}
}
fo(i,1,n) g[i][0]=a[i]=read();
fo(i,2,n) lg[i]=lg[i>>1]+1;
fo(j,1,lg[n]) fo(i,1,n-(1<<j)+1) g[i][j]=max(g[i][j-1],g[i+(1<<j-1)][j-1]);
sta[top=0]=0;
fo(i,1,n) {
while (top&&a[sta[top]]<=a[i]) top--;
L[i]=sta[top]+1;sta[++top]=i;
}
sta[top=0]=n+1;
fd(i,n,1) {
while (top&&a[sta[top]]<=a[i]) top--;
R[i]=sta[top]-1;sta[++top]=i;
}
fo(i,1,n) c[i].l=L[i],c[i].r=R[i],c[i].x=F(L[i],R[i]),c[i].y=a[i];
fo(i,1,m) ask[i].l=read(),ask[i].r=read(),ask[i].x=read(),ask[i].y=i;
sort(ask+1,ask+m+1,cmp1);
sort(c+1,c+n+1,cmp1);
fo(i,1,n<<2) tr[i]=inf;j=0;
fo(i,1,m) {
while (j<n&&c[j+1].x>=ask[i].x) {j++;ins(1,1,n,c[j].l,c[j].y);}
int id=ask[i].y,l=ask[i].l,r=ask[i].r,x=ask[i].x;
if (F(l,r)<x) {an[id]=-1;continue;}
an[id]=inf;
int L=l,R=r,pos;
while (L<=R) {
int mid=L+R>>1;
if (F(l,mid)>=x) pos=mid,R=mid-1;
else L=mid+1;
}
an[id]=min(an[id],query(l,pos));
L=l,R=r;
while (L<=R) {
int mid=L+R>>1;
if (F(mid,r)>=x) pos=mid,L=mid+1;
else R=mid-1;
}
an[id]=min(an[id],query(pos,r));
an[id]=min(an[id],que(1,1,n,l,pos));
}
fo(i,1,m) printf("%d\n",an[i]);
return 0;
}