题意
https://codeforces.com/contest/1037/problem/H
思考
贪心的思路是,尽可能多地找到读入串的一段前缀,然后再添上一个字典序比较大的字符。
先对原串建立SAM,考虑到有区间限制,需线段树合并维护endpos集合。
对于一个询问,我们现在SAM上找对它的前缀对应的节点。若存在,继续;否则就没必要找下去了。然后回溯这个过程,只要某个节点处出现大于当前字符的出边,直接输出答案。
时间复杂度$O(26*n*logn)$。
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1E5+5; 4 int n; 5 int size,head[maxn*4]; 6 int cnt,root[maxn*40],ls[maxn*40],rs[maxn*40],ans[maxn*40],what[maxn*40]; 7 struct edge 8 { 9 int to,next; 10 }E[maxn*2]; 11 inline void addE(int u,int v) 12 { 13 E[++size].to=v; 14 E[size].next=head[u]; 15 head[u]=size; 16 } 17 struct tree 18 { 19 int fa,len,ch[26]; 20 }; 21 void out(int l,int r,int num) 22 { 23 if(l==r) 24 { 25 cout<<l<<" "; 26 return; 27 } 28 int mid=(l+r)>>1; 29 if(ls[num]) 30 out(l,mid,ls[num]); 31 if(rs[num]) 32 out(mid+1,r,rs[num]); 33 } 34 void insertT(int l,int r,int pos,int&num,int pre) 35 { 36 num=++cnt; 37 ls[num]=ls[pre],rs[num]=rs[pre]; 38 if(l==r) 39 { 40 ans[num]=pos; 41 return; 42 } 43 int mid=(l+r)>>1; 44 if(pos<=mid) 45 insertT(l,mid,pos,ls[num],ls[pre]); 46 else 47 insertT(mid+1,r,pos,rs[num],rs[pre]); 48 ans[num]=max(ans[ls[num]],ans[rs[num]]); 49 } 50 int merge(int l,int r,int a,int b) 51 { 52 if(!a||!b) 53 return a|b; 54 int num=++cnt; 55 ans[num]=max(ans[a],ans[b]); 56 if(l==r) 57 return num; 58 int mid=(l+r)>>1; 59 ls[num]=merge(l,mid,ls[a],ls[b]); 60 rs[num]=merge(mid+1,r,rs[a],rs[b]); 61 ans[num]=max(ans[ls[num]],ans[rs[num]]); 62 return num; 63 } 64 int ask(int L,int R,int l,int r,int num) 65 { 66 if(!num) 67 return 0; 68 if(L<=l&&r<=R) 69 return ans[num]; 70 int mid=(l+r)>>1; 71 if(R<=mid) 72 return ask(L,R,l,mid,ls[num]); 73 else if(mid<L) 74 return ask(L,R,mid+1,r,rs[num]); 75 return max(ask(L,R,l,mid,ls[num]),ask(L,R,mid+1,r,rs[num])); 76 } 77 void dfs(int u) 78 { 79 for(int i=head[u];i;i=E[i].next) 80 { 81 int v=E[i].to; 82 dfs(v); 83 root[u]=merge(1,n,root[u],root[v]); 84 } 85 if(what[u]) 86 insertT(1,n,what[u],root[u],root[u]); 87 } 88 struct SAM 89 { 90 tree t[maxn*2]; 91 int last,tot; 92 SAM() 93 { 94 last=tot=1; 95 } 96 inline void add(int x,int pos) 97 { 98 int u=last,now=++tot; 99 last=tot; 100 what[now]=pos; 101 t[now].len=t[u].len+1; 102 for(;u&&!t[u].ch[x];u=t[u].fa) 103 t[u].ch[x]=now; 104 if(!u) 105 t[now].fa=1; 106 else 107 { 108 int v=t[u].ch[x]; 109 if(t[v].len==t[u].len+1) 110 t[now].fa=v; 111 else 112 { 113 int w=++tot; 114 t[w]=t[v]; 115 t[w].len=t[u].len+1; 116 t[now].fa=t[v].fa=w; 117 for(;u&&t[u].ch[x]==v;u=t[u].fa) 118 t[u].ch[x]=w; 119 } 120 } 121 } 122 void build() 123 { 124 for(int i=2;i<=tot;++i) 125 addE(t[i].fa,i); 126 } 127 }T; 128 int wait[maxn*2]; 129 void solve() 130 { 131 int L,R; 132 string str; 133 cin>>L>>R>>str; 134 int pos=1,top=0; 135 wait[top++]=pos; 136 for(int i=0;i<str.size();++i) 137 { 138 int x=str[i]-'a'; 139 if(T.t[pos].ch[x]) 140 { 141 pos=T.t[pos].ch[x]; 142 x=ask(L,R,1,n,root[pos]); 143 if(x-i<L) 144 break; 145 wait[top++]=pos; 146 } 147 else 148 break; 149 } 150 for(int i=top-1;i>=0;--i) 151 { 152 int x=max(str[i]-'a',-1); 153 for(int j=x+1;j<26;++j) 154 if(T.t[wait[i]].ch[j]) 155 { 156 int pos=T.t[wait[i]].ch[j]; 157 int x=ask(L,R,1,n,root[pos]); 158 if(x-i>=L) 159 { 160 for(int k=0;k<i;++k) 161 cout<<str[k]; 162 cout<<char('a'+j)<<endl; 163 return; 164 } 165 } 166 } 167 cout<<-1<<endl; 168 } 169 int main() 170 { 171 ios::sync_with_stdio(false); 172 string str; 173 cin>>str; 174 n=str.size(); 175 for(int i=0;i<str.size();++i) 176 T.add(str[i]-'a',i+1); 177 T.build(); 178 dfs(1); 179 int T; 180 cin>>T; 181 while(T--) 182 solve(); 183 return 0; 184 }