Codeforces 1037H Security sam+线段树合并
Codeforces 1037H Security
题意
给一个长度为\(n\)的字符串\(s\),\(q\)次询问,每次询问给出两个整数\(l,r\)和一个字符串\(x\),你要在区间\([l,r]\)中找到\(s\)的一个子串满足其字典序大于\(x\),输出满足条件的子串中字典序最小的子串,找不到输出\(-1\)。
\(n\le 10^5,q\le 2\cdot 10^5,\sum |s|\le 2\cdot 10^5\)
分析
用线段树维护后缀自动机上每个点\(u\)的终点集合\(endpos(u)\),对于每个询问,枚举\(x\)的每个前缀在\(sam\)上转移,再尝试去在后面添加一个更大的字符\(c\),判断转移到的点的\(endpos\)集合中有没有\([l,r]\)中的点,有则更新答案。
Code
#include<bits/stdc++.h>
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define per(i,n,x) for(int i=n;i>=x;i--)
#define sz(a) int(a.size())
#define rson mid+1,r,rs[p]
#define pii pair<int,int>
#define lson l,mid,ls[p]
#define ll long long
#define pb push_back
#define mp make_pair
#define se second
#define fi first
using namespace std;
const double eps=1e-8;
const int mod=1e9+7;
const int N=4e5+10;
const int inf=1e9;
int n,m;
char s[N],t[N];
vector<int>g[N];
struct SegmentTree{
int tr[N*40],ls[N*40],rs[N*40],tot;
void up(int x,int l,int r,int &p){
if(!p) p=++tot;
tr[p]++;
if(l==r) return;
int mid=l+r>>1;
if(x<=mid) up(x,lson);
else up(x,rson);
}
int merge(int x,int y,int l,int r){
if(!x||!y) return x+y;
int o=++tot,mid=l+r>>1;
if(l==r) tr[o]=tr[x]+tr[y];
else{
ls[o]=merge(ls[x],ls[y],l,mid);
rs[o]=merge(rs[x],rs[y],mid+1,r);
tr[o]=tr[ls[o]]+tr[rs[o]];
}
return o;
}
int qy(int dl,int dr,int l,int r,int p){
if(!p||l>r) return 0;
if(l==dl&&r==dr) return tr[p];
int mid=l+r>>1;
if(dr<=mid) return qy(dl,dr,lson);
else if(dl>mid) return qy(dl,dr,rson);
else return qy(dl,mid,lson)+qy(mid+1,dr,rson);
}
}seg;
struct SAM{
int last,cnt;int ch[N][26],fa[N],len[N],rt[N];
void insert(int c,int pos){
int p=last,np=++cnt;last=np;len[np]=len[p]+1;
for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
if(!p) fa[np]=1;
else {
int q=ch[p][c];
if(len[q]==len[p]+1) fa[np]=q;
else {
int nq=++cnt;len[nq]=len[p]+1;
memcpy(ch[nq],ch[q],sizeof ch[q]);
fa[nq]=fa[q],fa[q]=fa[np]=nq;
for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
}
}
seg.up(pos,1,n,rt[np]);
}
void init(){
last=cnt=1;
}
void dfs(int u){
for(int x:g[u]){
dfs(x);
rt[u]=seg.merge(rt[u],rt[x],1,n);
}
}
void gao(){
for(int i=2;i<=cnt;i++) g[fa[i]].pb(i);
dfs(1);
}
void solve(int l,int r){
int u=1;
t[m+1]='a'-1;
pii ans=mp(-1,-1);
for(int i=1;i<=m+1;i++){
for(int j=t[i]-'a'+1;j<26;j++){
int x=ch[u][j];
if(!x) continue;
int pos=seg.qy(l+i-1,r,1,n,rt[x]);
if(pos){
ans=mp(i,j);
break;
}
}
if(i==m+1||!ch[u][t[i]-'a']) break;
u=ch[u][t[i]-'a'];
}
if(ans==mp(-1,-1)) puts("-1");
else{
t[ans.fi]=0;
printf("%s%c\n",t+1,ans.se+'a');
}
}
}sam;
int main(){
scanf("%s",s+1);
n=strlen(s+1);
sam.init();
for(int i=1;i<=n;i++) sam.insert(s[i]-'a',i);
sam.gao();
int q,l,r;
scanf("%d",&q);
while(q--){
scanf("%d%d",&l,&r);
scanf("%s",t+1);
m=strlen(t+1);
sam.solve(l,r);
}
return 0;
}