CF1037H Security

题意:给出一个字符串 \(S\) ,给出 \(Q\) 个操作,给出\(L\) , \(R\) , \(T\) ,求字典序最小的\(S_1\),使得\(S_1\)\(S[L..R]\)的子串,且\(S_1\)的字典序严格大于\(T\)。输出这个\(S_1\),如果无解输出\(-1\)

\(SAM\) + 线段树合并

利用在 \(parent树\) 线段树合并维护 \({\rm endpos}(p)\) 并解决区间 \([l,r]\) 限制。

所以直接贪心地在 \(SAM\) 上跑,使跑出来的串尽可能接近 \(T\) ,即 \(S_1,{\rm strlen}(S_1)=n\) 中的 \([1,n-1]\)\(T\)\([1,n-1]\) 时相同的,只有第 \(n\) 位是不同的。

#include<iostream>
#include<cstdio>
#include<cstring>
#define R register int 
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
  register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
  do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=1000010,B=30;
int n,lst=1,tot=1,num;
int len[N],fa[N],c[N][26],d[N],mem[N];
char s[N],ans[N];
inline void add(int ch) {
  R p=lst,np=lst=++tot;
  len[np]=len[p]+1;
  while(p&&!c[p][ch]) c[p][ch]=np,p=fa[p];
  if(!p) return fa[np]=1,void();
  R q=c[p][ch];
  if(len[q]==len[p]+1) fa[np]=q;
  else {
    R nq=++tot;
    memcpy(c[nq],c[q],26<<2);
    fa[nq]=fa[q],len[nq]=len[p]+1;
    fa[np]=fa[q]=nq;
    while(p&&c[p][ch]==q) c[p][ch]=nq,p=fa[p];
  }
}
int rt[N],ls[N*B],rs[N*B],sum[N*B];
inline void change(int& tr,int l,int r,int p) {
  if(!tr) tr=++num;
  ++sum[tr]; if(l==r) return ;
  R md=(l+r)>>1;
  p<=md?change(ls[tr],l,md,p):change(rs[tr],md+1,r,p);
}
inline bool query(int tr,int l,int r,int LL,int RR) {
  if(LL<=l&&r<=RR) return sum[tr]; R md=(l+r)>>1;
  return (LL<=md&&ls[tr]&&query(ls[tr],l,md,LL,RR))
        ||(RR>md&&rs[tr]&&query(rs[tr],md+1,r,LL,RR));
}
inline int merge(int tr,int t,int l,int r) {
  if(!tr||!t) return tr+t;
  R p=++num,md=(l+r)>>1;
  sum[p]=sum[tr]+sum[t];
  if(l==r) return p;
  ls[p]=merge(ls[tr],ls[t],l,md);
  rs[p]=merge(rs[tr],rs[t],md+1,r);
  return p;
}
inline void solve(int l,int r) {
  R p=1,tot=1,m=strlen(s+1),ch;
  while(20040109) {
    ch=s[tot]-'a';
    ans[tot]='#';
    for(R i=max(ch+1,0);i<26;++i) 
      if(c[p][i]&&query(rt[c[p][i]],1,n,l+tot-1,r)) {
        ans[tot]=i+'a'; break;
      }
    if(tot==m+1||!c[p][ch]||
        !query(rt[c[p][ch]],1,n,l+tot-1,r)) break;
    p=c[p][ch];
    ++tot;
  } while(tot&&ans[tot]=='#') --tot; 
  if(!tot) return puts("-1"),void();
  for(R i=1;i<tot;++i) putchar(s[i]);
  putchar(ans[tot]),putchar(10);
}
inline void main() {
  scanf("%s",s+1),n=strlen(s+1);
  for(R i=1;i<=n;++i)   
    add(s[i]-'a'),change(rt[lst],1,n,i);
  for(R i=1;i<=tot;++i) ++d[len[i]];
  for(R i=1;i<=n;++i) d[i]+=d[i-1];
  for(R i=1;i<=tot;++i) mem[d[len[i]]--]=i;
  for(R i=tot;i;--i) { R u=mem[i];
    rt[fa[u]]=merge(rt[fa[u]],rt[u],1,n);
  } R T=g(); while(T--) {
    R l=g(),r=g();
    scanf("%s",s+1);
    solve(l,r);
  }
}
} signed main() {Luitaryi::main(); return 0;}

2020.01.10

posted @ 2020-01-10 18:33  LuitaryiJack  阅读(174)  评论(0编辑  收藏  举报