CF1037H Security 后缀自动机 + right集合线段树合并 + 贪心
题目描述:
给定一个字符串 $S$
给出 $Q$ 个操作,给出 $L,R,T$,求出字典序最小的 $S_{1}$ 为 $S[L...R]$的子串,且 $S_{1}$ 的字典序严格大于 $T$. 输出这个 $S_{1}$,如果无解输出 $-1$
不难想到 $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集合线段树合并 + 贪心的更多相关文章
- CF700E Cool Slogans 后缀自动机 + right集合线段树合并 + 树形DP
题目描述 给出一个长度为n的字符串s[1],由小写字母组成.定义一个字符串序列s[1....k],满足性质:s[i]在s[i-1] (i>=2)中出现至少两次(位置可重叠),问最大的k是多少,使 ...
- [BJWC2018]Border 的四种求法(后缀自动机+链分治+线段树合并)
题目描述 给一个小写字母字符串 S ,q 次询问每次给出 l,r ,求 s[l..r] 的 Border . Border: 对于给定的串 s ,最大的 i 使得 s[1..i] = s[|s|-i+ ...
- 【codeforces666E】Forensic Examination 广义后缀自动机+树上倍增+线段树合并
题目描述 给出 $S$ 串和 $m$ 个 $T_i$ 串,$q$ 次询问,每次询问给出 $l$ .$r$ .$x$ .$y$ ,求 $S_{x...y}$ 在 $T_l,T_{l+1},...,T_r ...
- CF547E Milk and Friends(AC自动机的fail指针上建主席树 或 广义后缀自动机的parent线段树合并)
What-The-Fatherland is a strange country! All phone numbers there are strings consisting of lowercas ...
- 模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合)
模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合) Code: #include <bits/stdc++.h> using namespace std; #define ...
- 洛谷P4770 [NOI2018]你的名字 [后缀自动机,线段树合并]
传送门 思路 按照套路,直接上后缀自动机. 部分分:\(l=1,r=|S|\) 首先把\(S\)和\(T\)的后缀自动机都建出来. 考虑枚举\(T\)中的右端点\(r\),查询以\(r\)结尾的串最长 ...
- BZOJ5417[Noi2018]你的名字——后缀自动机+线段树合并
题目链接: [Noi2018]你的名字 题目大意:给出一个字符串$S$及$q$次询问,每次询问一个字符串$T$有多少本质不同的子串不是$S[l,r]$的子串($S[l,r]$表示$S$串的第$l$个字 ...
- 【CF666E】Forensic Examination 广义后缀自动机+倍增+线段树合并
[CF666E]Forensic Examination 题意:给你一个字符串s和一个字符串集合$\{t_i\}$.有q个询问,每次给出$l,r,p_l,p_r$,问$s[p_l,p_r]$在$t_l ...
- [HEOI2016/TJOI2016]字符串(后缀数组+二分+主席树/后缀自动机+倍增+线段树合并)
后缀数组解法: 先二分最长前缀长度 \(len\),然后从 \(rnk[c]\) 向左右二分 \(l\) 和 \(r\) 使 \([l,r]\) 的 \(height\geq len\),然后在主席树 ...
随机推荐
- 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_06 Properties集合_2_Properties集合中的方法store
第一行是注释,第二行是时间,时间是自动加的 使用FileOutputStream. 写入中文会乱码
- Object not locked by thread before notify() in onPostExecute
Ask Question Asked 5 years, 4 months ago Active 3 years, 9 months ago Viewed 56k time 41 2 I try to ...
- laravel 设置自定义 Validator
转自:https://learnku.com/docs/laravel/5.4/validation/1234#custom-validation-rules 自定义验证规则 Laravel 提供了许 ...
- 000 (H5*) 知识点总结
https://note.youdao.com/ynoteshare1/index.html?id=ff02e616917fba868f39241c8383d7c7&type=note 目录 ...
- python基础循环语句练习
1.使用while循环输入 1 2 3 4 5 6 8 9 10 n = 1 while n < 11: if n == 7: pass else: print(n) n = n + 1 ...
- SQL查询结果增加序列号
SQL查询记录中增加序列号 根据学生成绩在查询结果中增加排名字段: 1.SELECT ROW_NUMBER() OVER (ORDER BY SCORE ASC) AS RANK,NAME,SCORE ...
- 旧接口注册LED字符驱动设备(动态映射)
#include <linux/init.h> // __init __exit #include <linux/module.h> // module_init module ...
- TP5.1+Vue前后端分离实践
配置: 主域名 www.demo.xyz 二级子域名 api.demo.xyz 列表项目其中api.demo.xyz加入了版本控制,使用的是URL路由传入方式 在route.php路由文件中配置,如下 ...
- 洛谷 - P4008 - 文本编辑器 - 无旋Treap
https://www.luogu.org/problem/P4008 无旋Treap也可以维护序列. 千万要注意要先判断p节点存在才进行Show操作,不然输出一个'\0'(或者RecBin里面的东西 ...
- http请求中的Content-Length作用机制与分块chunked
httpclient-4.5.9.jar org.apache.http: auth 身份 client 端 conn 连接 cookie 本地 impl: 实现 exe ...