给定一个串\(S\),每次查询一个区间\([l,r]\)和一个串\(T\)
求\([l,r]\)内字典序\(>T\)的最小的子串\(R\)
复习\(\text{SAM}\)
显然可以枚举\(T\)匹配\(R\)的长度,然后枚举下一位字符,判断形成的串是否在\([l,r]\)内有出现
匹配问题用\(\text{SAM}\)维护比较方便,求出匹配节点后,判断其\(\text{endpos}\)集是否包含所求范围
可以在线线段树合并,也可以将所所有询问离线后树状数组+\(\text{dfs}\)作差
const int N=2e5+10,INF=1e9+10;
int n,m;
char s[N];
int trans[N][26],link[N],len[N],End[N],cnt,lst;
void Extend(int c){
int p=lst,cur=++cnt; len[cur]=len[lst]+1,lst=cur;
End[cur]=len[cur];
while(~p && !trans[p][c]) trans[p][c]=cur,p=link[p];
if(p==-1){ link[cur]=0; return; }
int q=trans[p][c];
if(len[q]==len[p]+1){ link[cur]=q; return; }
int r=++cnt;
len[r]=len[p]+1,memcpy(trans[r],trans[q],104);
while(~p && trans[p][c]==q) trans[p][c]=r,p=link[p];
link[r]=link[q],link[q]=link[cur]=r;
}
const int M=N*32;
int ls[M],rs[M];
void Upd(int &p,int l,int r,int x){
p=++cnt;
if(l==r) return;
int mid=(l+r)>>1;
x<=mid?Upd(ls[p],l,mid,x):Upd(rs[p],mid+1,r,x);
}
int Uni(int x,int y) {
if(!x||!y) return x|y;
int z=++cnt;
ls[z]=Uni(ls[x],ls[y]),rs[z]=Uni(rs[x],rs[y]);
return z;
}
int Que(int p,int l,int r,int ql,int qr) {
if(ql>qr || !p) return 0;
if(ql<=l && r<=qr) return 1;
int mid=(l+r)>>1;
if(ql<=mid && Que(ls[p],l,mid,ql,qr)) return 1;
if(qr>mid && Que(rs[p],mid+1,r,ql,qr)) return 1;
return 0;
}
vector <int> G[N];
int rt[N];
void dfs(int u) {
if(End[u]) Upd(rt[u],1,n,End[u]);
for(int v:G[u]) dfs(v),rt[u]=Uni(rt[u],rt[v]);
}
int K[N];
void Solve(){
int l=rd(),r=rd();
scanf("%s",s+1),m=strlen(s+1),s[m+1]=‘a‘-1;
int p=0;
rep(i,1,m) {
K[i]=trans[K[i-1]][s[i]-‘a‘];
if(!K[i]) break;
p=i;
}
drep(i,p,0) {
rep(j,s[i+1]-‘a‘+1,25) {
int x=trans[K[i]][j];
if(!x) continue;
if(!Que(rt[x],1,n,l+i,r)) continue;
s[i+1]=j+‘a‘,s[i+2]=0,puts(s+1);
return;
}
}
puts("-1");
}
int main(){
link[0]=-1,scanf("%s",s+1),n=strlen(s+1);
rep(i,1,n) Extend(s[i]-‘a‘);
rep(i,1,cnt) G[link[i]].pb(i);
cnt=0,dfs(0);
rep(_,1,rd()) Solve();
}
原文:https://www.cnblogs.com/chasedeath/p/14812280.html