题目描述:

给定一个字符串 $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. Cannot refer to the non-final local variable user defined in an enclosing scope

    (1)首先该错误只会在 JDK 1.7 版本及其以前如果要在匿名内部类中报出,解决办法为在传入的参数前面增加final修饰,但如果在JDK 如果变更为1.8版本及其以后,该异常就不存在了. (2)如何 ...

  2. iView 实战系列教程(21课时)_2.iView 实战教程之导航、路由、鉴权篇

    在c盘创建一个iview-router的项目 . 然后使用默认的配置 跳过 添加vue-router的插件 编译我们的文件. 编译好之后,我们启动App 默认的页面就打开了. 默认两个路由一个是abo ...

  3. postman+newman+jenkins接口自动化

    postman用来做接口测试非常方便,接口较多时,则可以实现接口自动化 目录 1.环境准备 2.本机调试脚本 3.集成jenkins 1.环境准备 1.1安装nodejs6.0+ 安装nodejs6. ...

  4. GUI_FlowLayout

    void setBounds(x, y, width, height) 设置窗体坐标,窗体大小 import java.awt.Frame; public class IntegerDemo { pu ...

  5. spring boot 整合 RabbitMQ 错误

    1.错误 org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.spr ...

  6. charles_02_模拟弱网测试

    前言 用户使用app的场景是多变的,不一定稳定在WiFi或者4G网络下.大多数用户会在地铁.电梯等弱网情况下使用app,这些弱网情况下app常会出现一些数据丢失.闪退.页面展示不友好等情况.在测试过程 ...

  7. vue 组件传参

    路由配好了 再传个参呗 注:组件信息流转的时候只能单向1 > 父子传参传参:通过属性prop:传递数据 a.父组件传参给子组件 子组件: <ul> <li v-for=&quo ...

  8. oracle--单行函数和多行函数

    单行函数 1.字符函数 函  数 功  能 示  例 结 果 INITCAP (char) 首字母大写 initcap ('hello') Hello LOWER (char) 转换为小写 lower ...

  9. Node.js实战14:一个简单的TCP服务器。

    本文,将会展示如何用Nodejs内置的net模块开发一个TCP服务器,同时模拟一个客户端,并实现客户端和服务端交互. net模块是nodejs内置的基础网络模块,通过使用net,可以创建一个简单的tc ...

  10. Xilinx源语-------FDRE

    1.源语---FDRE FDRE代表一个单D型触发器,含的有五个信号分别为:  数据(data,D).时钟使能(Clock enable,CE).时钟(Clock).同步复位(synchronous ...