题目描述:

给定一个字符串 $S$

给出 $Q$ 个操作,给出 $L,R,T$,求出字典序最小的 $S_{1}$ 为 $S[L...R]$的子串,且 $S_{1}$ 的字典序严格大于 $T$. 输出这个 $S_{1}$,如果无解输出 $-1$

$1\leqslant|S|\leqslant10^5,1\leqslant Q\leqslant2\times10^5,1\leqslant L\leqslant R\leqslant |S|,\sum|T|\leqslant2\times10^5$
 题解:

正解还是比较好想的.
不难想到 $S_{1}$ 一定是与 $T$ 有一段相等的前缀并在一个位置上不同.
也就是说,$S_{1}=Prefix(T)+c$ ,$('a'\leqslant c\leqslant'z')$
先考虑没有 $L,R$ 的限制.
先将 $T$ 在后缀自动机上进行匹配,直到匹配不了.
贪心地从后向前枚举不同的那个字符,如果当前找到了不同字符,则直接输出即可. (这一定是最优的,因为前缀更长)
现在有了 $L,R$ 的限制,直接来一遍线段树合并维护 $right$ 集合即可.
在后缀自动机上匹配的时候到线段树中判断一下在不在 $[L,R]$ 中即可. 
#include<bits/stdc++.h>
#define setIO(s) freopen(s".in","r",stdin)
#define maxn 220000
using namespace std;
int n;
int rt[maxn];
namespace tr
{
#define mid ((l+r)>>1)
#define lson t[x].l
#define rson t[x].r
int cnt;
int newnode() { return ++cnt; }
struct Node{ int l,r,sumv; }t[maxn * 50];
int merge(int u,int v)
{
if(!u||!v) return u+v;
int x=newnode();
t[x].sumv=t[u].sumv+t[v].sumv;
lson=merge(t[u].l,t[v].l);
rson=merge(t[u].r,t[v].r);
return x;
}
void update(int &x,int l,int r,int k,int delta)
{
if(!x)x=newnode();
t[x].sumv+=delta;
if(l==r) return;
if(k<=mid) update(lson, l, mid, k, delta);
else update(rson, mid + 1, r, k, delta);
}
int query(int x,int l,int r,int L,int R)
{
if(!x || L>R)return 0;
if(l>=L&&r<=R) return t[x].sumv;
int tmp=0;
if(L<=mid) tmp+=query(lson,l,mid,L,R);
if(R>mid) tmp+=query(rson, mid+1,r,L,R);
return tmp;
}
#undef lson
#undef rson
};
namespace SAM
{
int tot,last;
int len[maxn], ch[maxn][30], f[maxn], rk[maxn], C[maxn];
void init() { tot = last = 1; }
void extend(int c)
{
int np=++tot,p=last;
last=np, len[np]=len[p]+1;
while(p&&!ch[p][c]) ch[p][c]=np,p=f[p];
if(!p) f[np]=1;
else
{
int q=ch[p][c];
if(len[q]==len[p]+1) f[np]=q;
else
{
int nq=++tot;
len[nq]=len[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
f[nq]=f[q],f[np]=f[q]=nq;
while(p&&ch[p][c]==q) ch[p][c]=nq, p=f[p];
}
}
tr::update(rt[np], 1, n, len[np], 1);
}
void prepare()
{
int i,j;
for(i=1;i<=tot;++i) ++C[len[i]];
for(i=1;i<=tot;++i) C[i]+=C[i-1];
for(i=1;i<=tot;++i) rk[C[len[i]]--]=i;
for(i=tot;i>=1;--i)
{
j=rk[i];
rt[f[j]]=tr::merge(rt[f[j]], rt[j]);
}
}
};
char str[maxn], T[maxn], stac[maxn];
int cur[maxn];
int main()
{
int i,j,Q;
// setIO("input");
scanf("%s",str+1);
n=strlen(str+1);
SAM::init();
for(i=1;i<=n;++i)
{
SAM::extend(str[i]-'a');
}
SAM::prepare();
scanf("%d",&Q);
while(Q--)
{
int l,r,_len,trace=0,top=0,L;
scanf("%d%d%s",&l,&r,T+1);
L=l;
_len=strlen(T+1);
cur[0]=1;
for(i=1;i<=min(_len,n-1);++i)
{
int c=T[i]-'a';
if(SAM::ch[cur[i-1]][c] && tr::query(rt[SAM::ch[cur[i-1]][c]], 1, n, l, r))
{
cur[i]=SAM::ch[cur[i-1]][c];
++l, trace=i, stac[++top]=T[i];
}
else break;
}
T[0]='a';
int flag=0;
for(i=min(n-1,trace);i>=0;--i)
{
int c= i + 1 > _len ? -1 : T[i+1] - 'a';
// if(flag) break;
for(j=c+1;j<27;++j)
{
if(SAM::ch[cur[i]][j] && tr::query(rt[SAM::ch[cur[i]][j]] , 1, n, l, r))
{
flag=1;
stac[++top]='a'+j;
break;
}
}
if(flag) break;
--l;
--top;
}
if(!flag) printf("-1\n");
else
{
for(i=1;i<=top;++i) printf("%c",stac[i]);
printf("\n");
}
}
return 0;
}

  

CF1037H Security 后缀自动机 + right集合线段树合并 + 贪心的更多相关文章

  1. CF700E Cool Slogans 后缀自动机 + right集合线段树合并 + 树形DP

    题目描述 给出一个长度为n的字符串s[1],由小写字母组成.定义一个字符串序列s[1....k],满足性质:s[i]在s[i-1] (i>=2)中出现至少两次(位置可重叠),问最大的k是多少,使 ...

  2. [BJWC2018]Border 的四种求法(后缀自动机+链分治+线段树合并)

    题目描述 给一个小写字母字符串 S ,q 次询问每次给出 l,r ,求 s[l..r] 的 Border . Border: 对于给定的串 s ,最大的 i 使得 s[1..i] = s[|s|-i+ ...

  3. 【codeforces666E】Forensic Examination 广义后缀自动机+树上倍增+线段树合并

    题目描述 给出 $S$ 串和 $m$ 个 $T_i$ 串,$q$ 次询问,每次询问给出 $l$ .$r$ .$x$ .$y$ ,求 $S_{x...y}$ 在 $T_l,T_{l+1},...,T_r ...

  4. CF547E Milk and Friends(AC自动机的fail指针上建主席树 或 广义后缀自动机的parent线段树合并)

    What-The-Fatherland is a strange country! All phone numbers there are strings consisting of lowercas ...

  5. 模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合)

    模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合) Code: #include <bits/stdc++.h> using namespace std; #define ...

  6. 洛谷P4770 [NOI2018]你的名字 [后缀自动机,线段树合并]

    传送门 思路 按照套路,直接上后缀自动机. 部分分:\(l=1,r=|S|\) 首先把\(S\)和\(T\)的后缀自动机都建出来. 考虑枚举\(T\)中的右端点\(r\),查询以\(r\)结尾的串最长 ...

  7. BZOJ5417[Noi2018]你的名字——后缀自动机+线段树合并

    题目链接: [Noi2018]你的名字 题目大意:给出一个字符串$S$及$q$次询问,每次询问一个字符串$T$有多少本质不同的子串不是$S[l,r]$的子串($S[l,r]$表示$S$串的第$l$个字 ...

  8. 【CF666E】Forensic Examination 广义后缀自动机+倍增+线段树合并

    [CF666E]Forensic Examination 题意:给你一个字符串s和一个字符串集合$\{t_i\}$.有q个询问,每次给出$l,r,p_l,p_r$,问$s[p_l,p_r]$在$t_l ...

  9. [HEOI2016/TJOI2016]字符串(后缀数组+二分+主席树/后缀自动机+倍增+线段树合并)

    后缀数组解法: 先二分最长前缀长度 \(len\),然后从 \(rnk[c]\) 向左右二分 \(l\) 和 \(r\) 使 \([l,r]\) 的 \(height\geq len\),然后在主席树 ...

随机推荐

  1. MVC 源码系列之控制器激活(二)之GetControllerType和GetcontrollerInstance

    GetControllerType和GetcontrollerInstance GetControllerType protected internal virtual Type GetControl ...

  2. nvm-windows编译源码 go遇到的问题

    异常: Microsoft Windows [Version 10.0.17134.1006] (c) Microsoft Corporation. All rights reserved. C:\U ...

  3. Pku2054 Color a Tree

    有一个N个结点的有根树,1是这个树的根.现在要对这N个结点依次进行染色,每个结点染色要花费1个单位的时候,同时要满足一个结点仅在其父亲被染色后才可被染色,每个结点有个权值Ci,如果我们在第Ti时间对i ...

  4. mooc-IDEA 列操作--005

    十一.IntelliJ IDEA -列操作 实例:根据HTTP请求JSON文件,生成一个枚举类 Step1:创建一个枚举类,把要转换的JSON串粘贴进来. 最终要实现效果 Step2:选中第一个100 ...

  5. Token 认证

    Token 认证 From今日头条:https://www.toutiao.com/i6516654967204348430/?tt_from=weixin&utm_campaign=clie ...

  6. [Markdown] 01 简单应用 第一弹

    目录 0. "调用函数前必先声明" 0.1 Table of Content 0.2 分割线 0.3 引用 0.4 标记 0.5 关于 html 0.6 代码块 用法 1 用法 2 ...

  7. winCE/Windows 应用程序消息提示框自动消失功能

    近期在做winCE系统的扫描枪应用程序,遇到了一些问题,其中包括消失提示框在手持终端显示过小, 用户要求提示框提示几秒后自动关闭,Windows平台可以通过调用系统API以定时器的方式进行自动销毁. ...

  8. ajax 的post方法 的content-type设置和express里应用body-parser

    ajax的post方法相比get方法,在传参形式上很不一样, get把参数用'?'拼接在端口后,并且用'&'连接;而post则是需要在send参数里设置. 根据ajax实例xhr.setReq ...

  9. [2019杭电多校第八场][hdu6667]Roundgod and Milk Tea

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6667 题目大意是说n个班级,每个班级有ai人和bi杯茶,每个人只能喝其他班的茶并且只能喝一杯.问最多有 ...

  10. 牛客练习赛51 C 勾股定理https://ac.nowcoder.com/acm/contest/1083/C

    题目描述 给出直角三角形其中一条边的长度n,你的任务是构造剩下的两条边,使这三条边能构成一个直角三角形. 输入描述: 一个整数n. 输出描述: 另外两条边b,c.答案不唯一,只要输出任意一组即为合理, ...